基本上,我已经完成了聚合以获得总数和组成总数的对象列表。
现在,我必须使用用于聚合的元素的聚合对象id来更新源表。基本上形成了两种关系。
coll.aggregate([
{ "$match": {"elig": 1, "nid" : null, "cncl" : null } },
{ "$group": {
"_id": "$nkey",
"cumqty": {"$sum": "$pr_qty.qty" },
"netted" : { "$push" : "$_id" }
}},
{ "$project": {
"nkey":"$nkey" ,
"cumqty": "$cumqty",
"netted" : "$netted" ,
"_id" : 0
}},
{ "$out": aggcollnm }
])
现在,聚合表中包含了使用$push生成的对象列表。
假设,doc1、doc2和doc3组成了agg1,而agg1的列表中有doc1、doc2和doc3。我希望doc1, doc2和doc3有agg1的id为nettid。
所以我做了下面的
coll.find().forEach( function(elem) {
coll.update (
{ "_id" : elem._id },
{ "$set" : { nid : aggcoll.aggregate ( [
{ "$unwind" : "$netted" } ,
{ "$match" : { "netted" : elem._id } },
{ "$project" : { "_id" :1 } }
] )._firstBatch[0]
}}
)
})
它在较小的集合中工作得很好。但对于1M文档失败与以下错误。
2014-06-30T09:48:40.577+0100错误:getMore:游标在服务器上不存在,可能重启或超时?在src/mongo shell/query.js: 116加载:./net .js失败
有更好的方法吗
您正在运行MongoDB 2.6,因此有方法可以更有效地更新以及您的一般处理似乎是相反的。你应该循环你的"aggcoll",然后从里面更新你的目标:
var batch = coll.initializeOrderedBulkOp();
counter = 0;
aggcoll.find().forEach(function(agg) {
batch.find({ "_id": { "$in": agg.netted }}).update({ "$set: { "nid": agg._id } });
counter++;
if ( counter % 1000 == 0 ) {
batch.execute();
counter = 0;
batch = coll.initializeOrderedBulkOp();
}
});
if ( counter > 0 )
batch.execute();
你的"内联"聚合语句并不是一个非常有效的方法来做你正在尝试的事情,并且会减慢很多事情。在这里,不仅通过 $in
发布所有匹配的_id
值的更新,因为这是一个"多"更新操作,而且批量操作API的一般使用减少了服务器的流量和时间。
说真的,我不知道你为什么要这样做,因为你应该已经有了"相关"信息。看一下您的原始聚合:
{ "$group": {
"_id": "$nkey",
由于某种原因,您更改了它,因此当您将其写出来时,它不再是这个新集合的_id
键。显然,该字段存在于您所引用的所有文档中,并且应该将其保留为新的主键。