使用 Knex,如何将连接表的相关行作为嵌套对象给出?

Posted

技术标签:

【中文标题】使用 Knex,如何将连接表的相关行作为嵌套对象给出?【英文标题】:Using Knex, how can the relevant rows of a joined table be given as a nested object? 【发布时间】:2020-04-18 15:00:40 【问题描述】:

使用 knex,我如何从 users 表中获取用户的相关行以及 id=1 的用户的所有组的数组?

这是我的users 表:

这是我的groups 表:

这是我的users_groups 关联表:

…我正在运行此查询,但它为同一用户返回 3 个单独的行:

db("users").join("users_groups", "users.id", "=", "users_groups.user_id").join("groups", "groups.id", "=", "users_groups.group_id").where("users.id", "=", 1)

我认为可以翻译成:

select * from users inner join users_groups on users.id = users_groups.user_id inner join groups on groups.id = users_groups.group_id where users.id=1

SQL 返回:

它正在返回:

Array(3) [Object, Object, Object]
length:3
__proto__:Array(0) [, …]
0:Object email:"raj@raj.raj" group_id:1, id:1, name:"step 1", name:"r", role:"superadmin", user_id:1, username:"raj"
1:Object email:"raj@raj.raj" group_id:2, id:1, name:"step 2", name:"r", role:"superadmin", user_id:1, username:"raj"
2:Object email:"raj@raj.raj" group_id:3, id:1, name:"step 3", name:"r", role:"superadmin", user_id:1, username:"raj"

字符串化,看起来是这样的

"["id":1,"name":"step 1","email":"raj@raj.raj","username":"raj","password":"$2b$10$GbbLTP2sEPS7OKmR4l8RSeX/PUmoIFyNBJb1RIIIrbZa1NNwolHFK","role":"superadmin","created_at":"2020-04-14T12:45:38.138Z","user_id":1,"group_id":1,"id":2,"name":"step 2","email":"raj@raj.raj","username":"raj","password":"$2b$10$GbbLTP2sEPS7OKmR4l8RSeX/PUmoIFyNBJb1RIIIrbZa1NNwolHFK","role":"superadmin","created_at":"2020-04-14T12:45:38.138Z","user_id":1,"group_id":2,"id":3,"name":"step 3","email":"raj@raj.raj","username":"raj","password":"$2b$10$GbbLTP2sEPS7OKmR4l8RSeX/PUmoIFyNBJb1RIIIrbZa1NNwolHFK","role":"superadmin","created_at":"2020-04-14T12:45:38.138Z","user_id":1,"group_id":3]"

我宁愿让它返回一个表示单个用户行的对象,并为groups 表中的 3 个相关行提供一个嵌套对象。例如:

id:1, name:"raj", groups:[id:1, name:"step 1", id:2,name:"step 2", id:3,name:"step 3"]

这可能吗?还是需要多次查询,这有多大的浪费?

【问题讨论】:

您应该使用像 objection.js 和 .withGraphFetched() 这样的 ORM 方法来获取相关对象作为嵌套对象。使用 objection.js 只是 knex 之上的一种实用程序层,它不会产生任何额外的开销,但会为您提供一堆额外的功能,从而使开发应用程序更加容易。 【参考方案1】:

Knex 无法根据需要聚合平面数据。你应该自己做。

(await db('users')
  .join('users_groups', 'users.id', '=', 'users_groups.user_id')
  .join('groups', 'groups.id', '=', 'users_groups.group_id')
  .where('users.id', '=', 1)
  )
  .reduce((result, row) => 
    result[row.id] = result[row.id] || 
      id: row.id,
      username: row.username,
      email: row.email,
      groups: [],
    ;

    result[row.id].groups.push( id: row.group_id, name: row.name );
    return result;
  , );

【讨论】:

这将返回包含 3 个对象的原始数组,但该行的组作为其自己的数组中的单个对象。比如:paste.ee/p/YO5EZ 这是结果的字符串化版本:paste.ee/p/W3hM7 我不确定这里的问题是什么,我的代码是否有意义? 我明白你的一般观点,但此代码返回 paste.ee/p/YO5EZ 而不是 paste.ee/p/77OUq 。目标结构是具有 groups 键的单个对象,其中包含 id=1 的用户的相关 groups 表列的数组。 行吗?因此,根据我的示例构建您的代码。

以上是关于使用 Knex,如何将连接表的相关行作为嵌套对象给出?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建一个结构连接行作为嵌套文档 PostgreSQL

如何在 RDS 上正确使用 Knex / Bookshelf 和 MySQL

Bookshelf.js / Knex.js 嵌套在单个查询中的位置

如何将对象数组作为道具传递给组件,然后将数组的成员作为道具传递给嵌套组件?

如何删除大型表的嵌套循环连接

依赖地狱——如何将依赖传递给深度嵌套的对象?