使用数组的 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 集合中创建 refUser 集合 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'
  },
  ...
]
*/