Node.js Mongoose游标,包含许多文档和加载

Node.js Mongoose游标,包含许多文档和加载,node.js,mongodb,express,mongoose,Node.js,Mongodb,Express,Mongoose,我们在Node.Js/Express中使用mongoose已经有一段时间了,我们不清楚的一件事是,当您使用find进行查询时,会发生什么情况,并且您有一个很大的文档结果集。例如,假设您希望遍历所有用户以执行一些低优先级的后台处理 let cursor = User.find({}).cursor(); cursor.on('data',function(user) { // do some processing here }); 我的理解是cursor.on('data')不会阻塞。因

我们在Node.Js/Express中使用mongoose已经有一段时间了,我们不清楚的一件事是,当您使用find进行查询时,会发生什么情况,并且您有一个很大的文档结果集。例如,假设您希望遍历所有用户以执行一些低优先级的后台处理

let cursor = User.find({}).cursor();
cursor.on('data',function(user) {
   // do some processing here 
});
我的理解是cursor.on('data')不会阻塞。因此,如果你有100000个用户,那么你几乎同时处理100000个用户的系统将无法承受。似乎没有“下一步”或其他方法来规范我们使用文档的能力


如何处理大型文档结果集

猫鼬确实有一个用于游标的
.next()
方法!看看这本书。以下是截至此答案的示例部分的快照:

// There are 2 ways to use a cursor. First, as a stream:
Thing.
  find({ name: /^hello/ }).
  cursor().
  on('data', function(doc) { console.log(doc); }).
  on('end', function() { console.log('Done!'); });

// Or you can use `.next()` to manually get the next doc in the stream.
// `.next()` returns a promise, so you can use promises or callbacks.
var cursor = Thing.find({ name: /^hello/ }).cursor();
cursor.next(function(error, doc) {
  console.log(doc);
});

// Because `.next()` returns a promise, you can use co
// to easily iterate through all documents without loading them
// all into memory.
co(function*() {
  const cursor = Thing.find({ name: /^hello/ }).cursor();
  for (let doc = yield cursor.next(); doc != null; doc = yield cursor.next()) {
    console.log(doc);
  }
});

考虑到上述情况,您的数据集可能会变得相当大,并且难以使用。考虑使用MunGDB来简化大型数据集的处理可能是个好主意。如果使用副本集,甚至可以设置
readPreference
将大型聚合查询定向到辅助节点,以确保主节点的性能基本不受影响。这将把负担从服务器转移到不太重要的辅助数据库节点

如果你的数据集特别大,而且你对同一个文档重复执行相同的计算,你甚至可以考虑将预先计算的聚合结果存储在一个“基础”文档中,然后将所有未处理的文档应用到那个“基”上作为一个“delta”——也就是说,你可以将计算量降低到“自上次保存计算以来的每次更改”

最后,还有一个负载平衡选项。您可以有多个应用服务器进行处理,并有一个负载平衡器在它们之间大致均匀地分配请求,以防止任何一台服务器变得不堪重负



有很多选项可供您选择,以避免您的系统因所有数据处理而不知所措的情况。您应该采用的策略将在很大程度上取决于您的特定用例。然而,在这种情况下,这似乎是一个假设性问题,因此可能需要注意其他策略你不必担心这些事情。现在,坚持使用
.next()
调用,你应该会没事的。

猫鼬确实有一个
.next()
游标方法!查看。以下是截至此答案的示例部分的快照:

// There are 2 ways to use a cursor. First, as a stream:
Thing.
  find({ name: /^hello/ }).
  cursor().
  on('data', function(doc) { console.log(doc); }).
  on('end', function() { console.log('Done!'); });

// Or you can use `.next()` to manually get the next doc in the stream.
// `.next()` returns a promise, so you can use promises or callbacks.
var cursor = Thing.find({ name: /^hello/ }).cursor();
cursor.next(function(error, doc) {
  console.log(doc);
});

// Because `.next()` returns a promise, you can use co
// to easily iterate through all documents without loading them
// all into memory.
co(function*() {
  const cursor = Thing.find({ name: /^hello/ }).cursor();
  for (let doc = yield cursor.next(); doc != null; doc = yield cursor.next()) {
    console.log(doc);
  }
});

上面提到的,你的数据集可能会变得相当大,而且很难处理。你可以考虑使用MunGDB来简化大型数据集的处理。如果你使用了一个副本集,你甚至可以设置一个<代码> Read Posivs/Cuffe >来指导你的大型聚合查询到SECON。dary节点,确保主节点的性能在很大程度上不受影响。这会将负担从服务器转移到不太重要的辅助数据库节点

如果您的数据集特别大,并且在相同的文档上重复执行相同的计算,您甚至可以考虑将预先计算的聚合结果存储在“基础”文档中,然后将所有未处理的文档应用在“基”上作为“delta”,也就是说,可以将计算量减少到“下一步”。自上次保存计算以来的每次更改”

最后,还有一个负载平衡选项。您可以有多个应用服务器进行处理,并有一个负载平衡器在它们之间大致均匀地分配请求,以防止任何一台服务器变得不堪重负



有很多选项可供您选择,以避免您的系统因所有数据处理而不知所措的情况。您应该采用的策略将在很大程度上取决于您的特定用例。然而,在这种情况下,这似乎是一个假设性问题,因此可能需要注意其他策略I’我不是你需要关心的事情。现在,坚持使用
。next()
调用,您应该没事。

我喜欢您的答案。我认为最大的收获是更多地考虑大型数据集的体系结构,而不是简单地做更多的工作或使用蛮力方法。在一些测试中,我们遇到了一些本机JS回调问题,因为我们遇到了堆栈超流问题(由于该站点名为stack overflow,因此很难在一侧搜索).在任何情况下,我都能从这个答案中看到曙光。我喜欢你的答案。我认为最大的收获是更多地考虑大型数据集的体系结构,而不是简单地做更多的工作或使用蛮力方法。在一些测试中,我们遇到了一些本机JS回调问题,因为我们遇到了堆栈超流问题(这一边很难搜索,因为这个网站名为stack overflow)。