一段时间以来,我们一直在Node.Js / Express中使用猫鼬,而我们不清楚的一件事是,当您使用find查询并拥有大量文档结果时会发生什么。例如,假设您要遍历所有用户以进行一些低优先级的后台处理。
let cursor = User.find({}).cursor();
cursor.on('data',function(user) {
// do some processing here
});
我的理解是cursor.on('data')不会阻塞。因此,假设您有100,000个用户,那么将使几乎同时处理100,000个人的系统不堪重负。似乎没有“下一步”或其他方法来规范我们使用文档的能力。
您如何处理大型文档结果集?
答案 0 :(得分:2)
猫鼬实际上确实有一个用于游标的.next()
方法!签出Mongoose documentation。这是此答案的示例部分的快照:
// 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);
}
});
考虑到上述情况,您的数据集可能会变得很大而难以使用。考虑使用MongoDB的aggregation pipeline简化大型数据集的处理,对您来说可能是个好主意。如果使用副本集,则甚至可以设置readPreference
来将大型聚合查询定向到辅助节点,从而确保主要节点的性能在很大程度上不受影响。这会将负担从服务器转移到不太重要的辅助数据库节点。
如果您的数据集特别大,并且您对相同的文档重复执行相同的计算,则您甚至可以考虑将预先计算的聚合结果存储在“基本”文档中,然后将所有未处理的文档应用于该“基本”文档中,如下所示: “增量”,也就是说,您可以将计算量减少到“自上次保存的计算以来的每次更改”。
最后,还有负载平衡选项。您可以有多个应用程序服务器进行处理,并有一个负载平衡器在它们之间大致均匀地分配请求,以防止任何一台服务器变得不堪重负。
您可以使用很多选项来避免系统被所有数据处理淹没的情况。您应该采用的策略在很大程度上取决于您的特定用例。但是,在这种情况下,这似乎是一个假设的问题,因此,所指出的其他策略可能不会成为您需要关注的事情。现在,坚持使用.next()
通话,就可以了。