繁体   English   中英

如何在Node.js中高效/快速地执行数组连接,类似于MongoDB $ lookup?

[英]How to perform array join in Node.js efficiently/fast similar to MongoDB $lookup?

我想在Node.js中执行$ lookup,类似于MongoDB的$ lookup aggreation。

我有一个解决方案,但我不确定它在两个数组中的每一个或更大的对象中使用更多对象的速度有多快。

let users = [
    {userId: 1, name: 'Mike'}, 
    {userId: 2, name: 'John'}
    ]
let comments = [
    {userId: 1, text: 'Hello'}, 
    {userId: 1, text: 'Hi'}, 
    {userId: 2, text: 'Hello'}
    ]

let commentsUsers = [
    {userId: 1, text: 'Hello', user: {userId: 1, name: 'Mike'}}, 
    {userId: 1, text: 'Hi', user: {userId: 1, name: 'Mike'}}, 
    {userId: 2, text: 'Hello', user: {userId: 2, name: 'John'}}
    ] //Desired result

我知道这可以通过ECMA6阵列轻松完成。 例如:

let commentsUsers = comments.map(comment => {comment, users.find(user => user.userId === comment.userId)} )

对于大量用户来说,这是一种有效的方法,例如。 1M用户。 lodash与这个或任何其他更专业的库相比如何? 是否有更好的方法与香草JS这样做,例如。 使用Array.prototype.reduce()? 可以以任何方式使用索引来提高连接的性能吗?

编辑:

我的理想解决方案

 let users = [{userId:1,name:'Mike'},{userId:2,name:'John'}] let comments = [{userId:1,text:'Hello'},{userId:1,text:'Hi'},{userId:2,text:'Hello'}]; let usersMap = new Map(users.map(user => [user.userId, user])) let commentsUsers = comments.map(comment => ({...comment, user: usersMap.get(comment.userId)})) console.log(commentsUsers) 

感谢您的反馈!

您想要的结果不是正确的数据结构。 您缺少对象的关键字,例如{userId: 1, name: 'Mike'} 我添加了user作为索引解决方案的键值。

首先,我创建一个Map ,其中userId将成为我们的循环值。 之后,我只是使用map迭代comments ,将每个对象转换为包含所有comment信息和新的kv用户对象的新对象。 对于那对,我们不再需要使用find ,而是我们有一个简单的HashMap get调用。

时间复杂度方面,这将代码从O(n ^ 2)更改为O(n)

 let users = [{userId:1,name:'Mike'},{userId:2,name:'John'}], comments = [{userId:1,text:'Hello'},{userId:1,text:'Hi'},{userId:2,text:'Hello'}]; function mergeCommentUser(users, comments) { let map = new Map(users.map(v => [v.userId, v])); return comments.map(o => ({...o, user: map.get(o.userId)})); } console.log(JSON.stringify(mergeCommentUser(users,comments))) 

根据您的需要(以及节省冗余),您还可以更改以下行:

let map = new Map(users.map(v => [v.userId, v]));

改为:

let map = new Map(users.map(v => [v.userId, v.name]));

通过这样你的结果看起来像:

[
    {"userId":1,"text":"Hello","user":"Mike"},
    {"userId":1,"text":"Hi","user":"Mike"},
    {"userId":2,"text":"Hello","user":"Paul"}
]

否则,您可以省略comment.userId ,而是将完整用户添加到对象,以获得另一种避免冗余的方法。

目前,您提供的代码示例是O(n * m),或O(n 2 )。 您可以在users数组中创建每个userId及其各自索引的映射,然后您可以通过索引直接访问它而不是查找用户。 这将减少到O(n + m)的时间,即O(n)。

代码看起来像这样:

 const users = [{ userId: 1, name: "Mike" }, { userId: 2, name: "John" }]; const comments = [ { userId: 1, text: "Hello" }, { userId: 1, text: "Hi" }, { userId: 2, text: "Hello" } ]; const map = new Map(users.map((o, i) => [o.userId, i])); console.log( comments.map(o => { const index = map.get(o.userId); return index !== undefined ? { comment: o.text, user: users[index] } : o; }) ); 

显然,您可以修改最终结果,但这种方法比您提出的方法更有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM