我有一个简单的元素集合
{_id: n, xs: [...]}
我正在尝试计算所有数组中的元素总数
db.testRace.aggregate([{ $unwind : "$xs" }, { $group : { _id : null, count : { $sum : 1 } } }])
除非我开始对此系列进行大量更新,否则它的效果很好。在负载较重的更新操作中,我总得错 - 比它应该略大。
可以轻松复制。 首先生成一些测试数据
for(var i = 1; i <= 1000000; i++) {
db.testRace.insert({_id: i, xs: [i]});
}
然后模拟大量更新
while(true) {
var id = Math.floor((Math.random() * 1000000) + 1);
var obj = db.testRace.find({_id: id}).next();
obj.some="change";
db.testRace.update({_id: id}, obj);
}
在运行时会进行聚合展开查询。 没有加载我得到了正确的结果 - 1000000.但是当有很多更新时我会得到更大的数字,比如1001456。
如果我像这样运行查询
db.testRace.aggregate([{ $unwind : "$xs" }, {$group: {_id:"$xs", count:{$sum: 1}}}, { $sort : { count : -1 } }, { $limit : 2 }]);
我得到了
"result" : [
{
"_id" : 996972,
"count" : 2
},
{
"_id" : 997789,
"count" : 2
}
],
所以似乎聚合计数了两次记录。
是预期的行为还是我聚合错了?
我测试了本地mongodb实例,版本 - 2.4.9
答案 0 :(得分:1)
由于MongoDB处理读隔离的方式,这是预期的行为。如果您有一个长时间运行的查询(并且读取每个文档的聚合是一个长时间运行的查询),在查询期间对该数据进行更新,则可能会影响查询中是否返回更新的数据 - 具体取决于发生时的情况,你可能会错过一份文件,接收或接收两次。
来自源代码:
在收益期间插入,删除或修改任何数据 查询返回的查询可能会也可能不会被该查询返回。该 查询可以返回:没有;以前的数据;之后的数据;或两者 之前的数据和之后的数据。
简而言之,查询和查询之间没有隔离 插入/删除/更新。 AKA,READ_UNCOMMITTED。
https://github.com/mongodb/mongo/blob/master/src/mongo/db/exec/plan_stage.h
您的聚合查询正在产生中间查询,在此期间会更新某些数据。这会影响查询结果。