【问题标题】:SQL-joining of two or more arrays in JavaScriptJavaScript 中两个或多个数组的 SQL 连接
【发布时间】:2016-05-26 15:03:41
【问题描述】:

我有一个包含几个数组的单页网络应用程序,这些数组在逻辑上是链接的:来自“用户”的记录指的是“user_types”中的记录,“费用”指的是“用户”等:

var users = [
    { id:   "u0001", name: "John",      user_type_id: "1" },
    { id:   "u0002", name: "Bob",       user_type_id: "1" },
    { id:   "u0003", name: "Alice",     user_type_id: "5" },
    { id:   "u0004", name: "Jennifer",  user_type_id: "5" },
    // ... more
];

var user_types = [
    { id: "1", name: "Regular Clients"},
    { id: "5", name: "VIP Clients"},
    // ... more
];

var charges = [
    { id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
    { id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
    { id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
    { id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
    { id: "7469", user_id: null   , date: "2016-01-01", amount: "3.99", },
    // ... more
];

我需要以链接的方式显示它们,类似于以下SQL的产物:

SELECT 
     charges.date, 
     charges.amount, 
     users.name, 
     user_types.name
FROM 
     charges
          LEFT OUTER JOIN users ON users.id = charges.user_id
          LEFT OUTER JOIN user_types ON user_types.id = users.user_type_id

我知道我可以在服务器上使用此 SQL 查询创建 API 调用,但我想避免这种情况,因为表已经加载到 Web 应用程序中。

将它们加入记忆的最简单方法是什么?

【问题讨论】:

  • 你愿意使用库还是纯JS?这些数组中有多少数据?它们很大吗?
  • 你已经回答了你自己的问题:用 SQL 来做。然后更新您应用中的数据以匹配。
  • 另外,如何生成/填充数组?如果您可以修改它们的填充方式,您可以在需要加入它们时使事情变得更容易。
  • IMTheNachoMan:小型JS库还可以。 “Charges”数组通常是几百条记录,但应该能够处理几千条。 “用户”只有几百个。

标签: javascript sql arrays


【解决方案1】:

如果小库没问题,可以用StrelkiJS

var users = new StrelkiJS.IndexedArray();
users.loadArray([
        { id:   "u0001", name: "John",      user_type_id: "1" },
        { id:   "u0002", name: "Bob",       user_type_id: "1" },
        { id:   "u0003", name: "Alice",     user_type_id: "5" },
        { id:   "u0004", name: "Jennifer",  user_type_id: "5" },
        // ... more
    ]);
var user_types = new StrelkiJS.IndexedArray();
user_types.loadArray([
        { id: "1", name: "Regular Clients"},
        { id: "5", name: "VIP Clients"},
        // ... more
    ]);
var charges = new StrelkiJS.IndexedArray();
charges.loadArray([
        { id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
        { id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
        { id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
        { id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
        { id: "7469", user_id: null   , date: "2016-01-01", amount: "3.99", },
        // ... more
    ]);

var result = charges.query([{
    from_col: "user_id",
    to_table: users,
    to_col: "id",
    type: "outer",
    join: [{
        from_col: "user_type_id",
        to_table: user_types,
        to_col: "id",
        type: "outer",
    }]
}])

结果将加入以下结构的数组:

[
    [
        {"id":"7443","user_id":"u0001","date":"2016-01-01","amount":"3.99"},
        {"id":"u0001","name":"John","user_type_id":"1"},
        {"id":"1","name":"Regular Clients"}
    ],
    [
        {"id":"7445","user_id":"u0001","date":"2016-01-01","amount":"4.02"},
        {"id":"u0001","name":"John","user_type_id":"1"},
        {"id":"1","name":"Regular Clients"}
    ],
    [
        {"id":"7448","user_id":"u0001","date":"2016-01-01","amount":"6.99"},
        {"id":"u0001","name":"John","user_type_id":"1"},
        {"id":"1","name":"Regular Clients"}
    ],
    [
        {"id":"7453","user_id":"u0003","date":"2016-01-01","amount":"3.00"},
        {"id":"u0003","name":"Alice","user_type_id":"5"},
        {"id":"5","name":"VIP Clients"}
    ],
    [
        {"id":"7469","user_id":null,"date":"2016-01-01","amount":"3.99"},
        null,
        null
    ]
]

【讨论】:

  • 这看起来很完美。谢谢!
【解决方案2】:

如果您可以修改 usersuser_types 的填充方式,那么您可以很快地做到这一点。

您需要将 usersuser_types 更改为对象,这样您就有了这样的东西:

// make users an object with the id as the key
var users = {
	"u0001" : { name: "John",      user_type_id: "1" },
	"u0002" : { name: "Bob",       user_type_id: "1" },
	"u0003" : { name: "Alice",     user_type_id: "5" },
	"u0004" : { name: "Jennifer",  user_type_id: "5" }
};

// same for user_types
var user_types = {
	"1" : { name: "Regular Clients" },
	"5" : { name: "VIP Clients" }
};

var charges = [
	{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
	{ id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
	{ id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
	{ id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
	{ id: "7469", user_id: null   , date: "2016-01-01", amount: "3.99", }
];

// now you can just loop through and use object key lookups:

var out = [];

for(var i = 0, numCharges = charges.length; i < numCharges; ++i)
{
	var currentCharge = charges[i];
	
	if(currentCharge.user_id === null) continue;
	
	out.push([
		currentCharge.date,
		currentCharge.amount,
        
        // get the current charges user_id and look up the name from users
		users[currentCharge.user_id].name,
        
        // same as above but use the user_type_id to get the user_type name
		user_types[users[currentCharge.user_id].user_type_id].name
	]);
}

console.log(out);

【讨论】:

    【解决方案3】:

    该提案以IMTheNachoMan 解决方案为特色,扩展了从给定数据生成必要对象的功能。

    它包括charges所有行,因为使用 SQL,也会返回行。

    null 值的问题在这里测试,然后返回 null

    var users = [{ id: "u0001", name: "John", user_type_id: "1" }, { id: "u0002", name: "Bob", user_type_id: "1" }, { id: "u0003", name: "Alice", user_type_id: "5" }, { id: "u0004", name: "Jennifer", user_type_id: "5" }],
        user_types = [{ id: "1", name: "Regular Clients" }, { id: "5", name: "VIP Clients" }],
        charges = [{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", }, { id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", }, { id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", }, { id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", }, { id: "7469", user_id: null, date: "2016-01-01", amount: "3.99", }],
        user = Object.create(null),
        type = Object.create(null),
        result;
    
    users.forEach(function (u) {
        user[u.id] = u;
    });
    
    user_types.forEach(function (t) {
        type[t.id] = t;
    });
    
    result = charges.map(function (charge) {
        return {
            'charges.date': charge.date,
            'charges.amount': charge.amount,
            'users.name': charge.user_id === null ? null : user[charge.user_id].name,
            'user_types': charge.user_id === null ? null : type[user[charge.user_id].user_type_id].name,
        };
    });
    
    console.log(result);

    【讨论】:

      【解决方案4】:

      users 制作成地图,以便您可以使用users['u0001']。然后循环通过charges 并执行users[current_charge.user_id].charges.push(current_charge)users 中的每个用户都应该有一个 charges 属性初始化为一个空数组。当您将 users 数组转换为 id =&gt; user 映射时,您可以这样做。

      这里不需要什么特别的东西,只需通过userscharges 循环两次:

      var users_map = {};
      var i;
      for(i = 0; i < users.length; i++) {
          users_map[users[i].id] = users[i];
          users_map[users[i].id].charges = [];
      }
      
      for(i = 0; i < charges.length; i++) {
          users_map[charge[i].user_id].charges.push(charge[i]);
      }
      

      如果你真的需要最终的“结果”是一个数组,而不是一个map,你可以再次循环users_map,把它变成一个数组。 利用现代 JS 东西的一个非常简单的解决方案是:

      var joined_data = Object.keys(users_map).map(function (key) {
          return users_map[key];
      });
      

      您可以使用 lodash 或其他类似的库使上述代码更漂亮。

      【讨论】:

        【解决方案5】:

        不重构对象的唯一方法是循环和过滤。 您可以通过首先处理用户及其类型来稍微优化它,但仅此而已...

        var users = [
            { id:   "u0001", name: "John",      user_type_id: "1" },
            { id:   "u0002", name: "Bob",       user_type_id: "1" },
            { id:   "u0003", name: "Alice",     user_type_id: "5" },
            { id:   "u0004", name: "Jennifer",  user_type_id: "5" },
            // ... more
        ];
        
        var user_types = [
            { id: "1", name: "Regular Clients"},
            { id: "5", name: "VIP Clients"},
            // ... more
        ];
        
        var charges = [
            { id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
            { id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
            { id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
            { id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
            { id: "7469", user_id: null   , date: "2016-01-01", amount: "3.99", },
            // ... more
        ];
        
        // pre-process users
        var usersPlusTypes = users.map(function(u) {
          var foundUserTypes = user_types.filter(function(ut) {
            return ut.id == u.user_type_id;
          });
        
          return {
            id: u.id,
            user: u,
            userType: foundUserTypes.length ? foundUserTypes[0] : null
          }
        })
        
        // now link charges to users
        var results = charges.map(function(c) {
          var user = usersPlusTypes.filter(function(upt) {
            return upt.id == c.user_id;
          });
          
          return {
            date: c.date,
            amount: c.amount,
            userName: user.length ? user[0].user.name : null,
            userTypeName: user.length && user[0].userType ? user[0].userType.name : null,
          };
        });
        
        console.log(results);

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-11-06
          • 1970-01-01
          • 1970-01-01
          • 2015-10-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-24
          相关资源
          最近更新 更多