使用数组的 NodeJS 性能
NodeJS Performance with working with arrays
我想在 NodeJS 和 MongoDB.
中检索用户与来自不同 collection 的相应用户的聊天记录
NodeJS 的本质让我有一种不好的感觉,即 运行 以下代码将阻止或降低我的应用程序的性能。我可以复制一些数据,但我想了解有关 NodeJS 的更多信息。
请让我知道我的代码是否正常并且不会降低性能。
这里我获取了 20 个聊天记录。我也需要他们对应的用户。
然后我得到 userIds
并针对 User
collection 执行另一个查询。
现在我都有了,但我应该使用 Array.map
.
合并它们
我不使用 $lookup
因为我的 collection 是分片的。
$lookup
Performs a left outer join to an unsharded collection in the same database to filter in documents from the "joined" collection for processing. To each input document, the $lookup stage adds a new array field whose elements are the matching documents from the "joined" collection. The $lookup stage passes these reshaped documents to the next stage.
https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/#mongodb-pipeline-pipe.-lookup
let chats = await Chat.find({ active: true }).limit(20);
/*
[
{_id: ..., userId: 1, title: 'Chat A'},
...
]
*/
const userIds = chats.map(item => item.userId);
/*
[1, ...]
*/
const users = await User.find({ _id: { $in: userIds }});
/*
[
{_id: 1, fullName: 'Jack'},
...
]
*/
chats = chats.map(item => {
item.user = users.find(user => user._id === item.userId);
return item;
});
/*
[
{
_id: ...,
userId: 1,
user: {_id: 1, fullName: 'Jack'}, // <-------- added
title: 'Chat A'
},
...
]
*/
您不应该这样做。 MongoDB 有一个称为聚合框架的东西,$lookup pipeline 只需 1 个 MongoDB 查询即可自动为您完成。
但是因为你使用的是 Mongoose,这个查询变得更加简单,因为你可以使用 Mongoose 的 populate()
方法。所以你的整个代码可以用这样的一行替换:
const chats = await Chat.find({ active: true }).populate('userId;).limit(20);
console.log(chats)
注意:如果你的集合是分片的,在我看来你已经以最好的方式实现了逻辑。
您正在使用 async/await,因此您的代码将在每次使用 await
时等待响应
// Wait to finish here
let chats = await Chat.find({ active: true }).limit(20);
/*
[
{_id: ..., userId: 1, title: 'Chat A'},
...
]
*/
// Wait to finish here too
const users = await User.find({ _id: { $in: userIds }});
/*
[
{_id: 1, fullName: 'Jack'},
...
]
*/
因此,如果您的数据太多并且您的集合中没有任何索引,则完成这些查询的时间会太长。
在这种情况下,您应该在 Chat
集合中创建 ref
到 User
集合 chat.userId = user._id
然后当你调用查询聊天时,你 populate
字段 userId
这样你就不必映射 const userIds = chats.map(item => item.userId);
和 chats = chats.map...
聊天模式示例
const { Schema, model } = require("mongoose");
const chatSchema = new Schema({
active: Boolean,
userId: {
type: "ObjectId",
ref: "User",
},
title: String,
message: String
// another property
});
const userSchema = new Schema({
username: String,
email: String
// another property
})
// query for chat
const chatModel = new model('chat', chatSchema)
let chats = await chatModel.find({ active: true }).populate('userId').limit(20);
/*
[
{
_id: ...,
userId: {_id: 1, fullName: 'Jack'}, // <-------- already have
title: 'Chat A'
},
...
]
*/
我想在 NodeJS 和 MongoDB.
中检索用户与来自不同 collection 的相应用户的聊天记录
NodeJS 的本质让我有一种不好的感觉,即 运行 以下代码将阻止或降低我的应用程序的性能。我可以复制一些数据,但我想了解有关 NodeJS 的更多信息。
请让我知道我的代码是否正常并且不会降低性能。
这里我获取了 20 个聊天记录。我也需要他们对应的用户。
然后我得到 userIds
并针对 User
collection 执行另一个查询。
现在我都有了,但我应该使用 Array.map
.
我不使用 $lookup
因为我的 collection 是分片的。
$lookup
Performs a left outer join to an unsharded collection in the same database to filter in documents from the "joined" collection for processing. To each input document, the $lookup stage adds a new array field whose elements are the matching documents from the "joined" collection. The $lookup stage passes these reshaped documents to the next stage. https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/#mongodb-pipeline-pipe.-lookup
let chats = await Chat.find({ active: true }).limit(20);
/*
[
{_id: ..., userId: 1, title: 'Chat A'},
...
]
*/
const userIds = chats.map(item => item.userId);
/*
[1, ...]
*/
const users = await User.find({ _id: { $in: userIds }});
/*
[
{_id: 1, fullName: 'Jack'},
...
]
*/
chats = chats.map(item => {
item.user = users.find(user => user._id === item.userId);
return item;
});
/*
[
{
_id: ...,
userId: 1,
user: {_id: 1, fullName: 'Jack'}, // <-------- added
title: 'Chat A'
},
...
]
*/
您不应该这样做。 MongoDB 有一个称为聚合框架的东西,$lookup pipeline 只需 1 个 MongoDB 查询即可自动为您完成。
但是因为你使用的是 Mongoose,这个查询变得更加简单,因为你可以使用 Mongoose 的 populate()
方法。所以你的整个代码可以用这样的一行替换:
const chats = await Chat.find({ active: true }).populate('userId;).limit(20);
console.log(chats)
注意:如果你的集合是分片的,在我看来你已经以最好的方式实现了逻辑。
您正在使用 async/await,因此您的代码将在每次使用 await
// Wait to finish here
let chats = await Chat.find({ active: true }).limit(20);
/*
[
{_id: ..., userId: 1, title: 'Chat A'},
...
]
*/
// Wait to finish here too
const users = await User.find({ _id: { $in: userIds }});
/*
[
{_id: 1, fullName: 'Jack'},
...
]
*/
因此,如果您的数据太多并且您的集合中没有任何索引,则完成这些查询的时间会太长。
在这种情况下,您应该在 Chat
集合中创建 ref
到 User
集合 chat.userId = user._id
然后当你调用查询聊天时,你 populate
字段 userId
这样你就不必映射 const userIds = chats.map(item => item.userId);
和 chats = chats.map...
聊天模式示例
const { Schema, model } = require("mongoose");
const chatSchema = new Schema({
active: Boolean,
userId: {
type: "ObjectId",
ref: "User",
},
title: String,
message: String
// another property
});
const userSchema = new Schema({
username: String,
email: String
// another property
})
// query for chat
const chatModel = new model('chat', chatSchema)
let chats = await chatModel.find({ active: true }).populate('userId').limit(20);
/*
[
{
_id: ...,
userId: {_id: 1, fullName: 'Jack'}, // <-------- already have
title: 'Chat A'
},
...
]
*/