在javascript中将大量数据库结果转换为对象数组

问题描述 投票:0回答:3

我正在提取具有以下信息的数据库查询:

id, name, roleId, roleTitle

在查询中,我正在拉动用户及其角色。每个用户可以拥有0到N个角色。我想最终得到一个像这样的对象:

{
    id
    name
    roles: [{
       id
       title
    }]
}

这样做最有效的方法是什么?目前我正在做这样的事情:

const data = [];
arr.forEach((u) => {
   const index = data.findIndex(x => x.id === u.id);
    if (index >= 0) {
      data[index].roles.push({ id: u.roleId, title: u.roleTitle });
    } else {
      data.push({
        id: u.id,
        name: u.name,
        roles: u.roleId ? [{
          id: u.roleId,
          title: u.roleTitle,
        }] : [],
      });
    }
}

此解决方案正常工作但不确定如果我们将用户数量扩展到10k,每个用户的平均角色为3或50k,每个用户有5个角色,这是否是完成此操作的最快方法

javascript node.js
3个回答
2
投票

你最好的选择是在SQL中实现这一切,因为你正在为你的数据库使用PostgreSQL(如评论中所述)。我不知道你的表和列的确切名称,所以你可能需要调整它,但这会得到你想要的:

SELECT json_agg(t)
FROM (
  SELECT
    u.id,
    u.name,
    ro.roles
  FROM "user" u
  LEFT JOIN (
    SELECT
      ur.user_id,
      json_agg(
        json_build_object(
          'id', r.id,
          'title', r.title
        )
      ) AS roles
    FROM user_role ur
    LEFT JOIN "role" r ON r.id = ur.role_id
    GROUP BY ur.user_id
  ) ro ON ro.user_id = u.id
) t;

SQL小提琴:http://www.sqlfiddle.com/#!17/5f6ca/11

Explanation

json_build_object将使用指定的名称/值对创建对象,因此:

json_build_object(
  'id', r.id,
  'title', r.title
)

将角色idtitle组合成一个JSON对象,如下所示:

{id: 1, title: "Title 1"}

json_agg将多行聚合到一个JSON数组中,因此它将上面的角色对象转换为单个列,这是每个用户的角色对象数组(感谢内部子查询的GROUP BY u.id部分)。内部子查询为我们提供了这样的结果集(每个用户一行)

| user_id |                       roles                          |
|---------|------------------------------------------------------|
|    1    | [{id: 1, title: "Role 1"}, {id: 2, title: "Role 2"}] |

然后子查询连接到用户表,并且所有这些都包含在另一个子查询中,因此可以在整个结果上使用json_agg并返回单个json对象,该对象是具有角色的用户数组。


1
投票

这几乎肯定不是最有效的版本,但比你现在正在做的更快:

const data = Object.values(arr.reduce((obj, {id, name, roleId, roleTitle}) => {
  if (!(id in obj)) {
    obj[id] = {
      id,
      name,
      roles: {},
    };
  }
  if (!obj[id].roles[roleId]) {
    obj[id].roles[roleId] = {
      id: roleId,
      title: roleTitle,
    };
  }
  return obj;
}, {}));

通过使用对象(散列)而不是数组,确定用户是否已经存在或者用户是否已经具有角色是恒定时间O(1)操作(散列函数的成本)。但是,根据所使用的搜索方法,搜索数组在最坏的情况下是线性的O(n),甚至最好的情况是O(log n)。

您可以选择随风而变化的微优化兔子洞,但选择正确的数据结构和算法通常可以让您获得最优惠的优势。

我已经使用Object.values转换回最后的数组,如果省略这个并且只是坚持使用它可能会更快。


0
投票

希望这可以帮助。

var modified_array = function(xs, key) {
  return xs.reduce(function(rv, x) {
    obj = (rv[x[key]] = rv[x[key]] || {});
    obj.id = x.id;
    obj.name = x.name;
    obj.roles = obj.roles || []
    obj.roles.push({ id: x.roleId, title: x.roleTitle})
    return rv;
  }, {});
};

arr = [{id:1,name:"abd",roleId: 10,roleTitle: "hello"},
       {id:1, name: "abd", roleId: 15,roleTitle: "fello"}]    
console.log( Object.values(modified_array(arr, 'id')));
© www.soinside.com 2019 - 2024. All rights reserved.