使用 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,如何将连接表的相关行作为嵌套对象给出?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 RDS 上正确使用 Knex / Bookshelf 和 MySQL
Bookshelf.js / Knex.js 嵌套在单个查询中的位置