基本上,我已经完成聚合以获得构成总数的对象的总数和列表。
现在,我必须使用聚合对象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形成的obj id列表。
Say,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 无法加载:./ netting.js
有没有更好的方法来做到这一点。
答案 0 :(得分:1)
您正在运行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
值上发布更新,因为这是一个“多”更新操作,而且bulk operations API的一般用途也减少了到服务器的流量和时间。
实际上,我不知道为什么你这样做,因为你应该已经有了“相关”的信息。看看你的原始聚合:
{ "$group": {
"_id": "$nkey",
出于某种原因,您更改了此内容,以便在您将其写出时不再是此新集合的_id
键。显然,该字段存在于您采购的所有文档中,并且应该将其保留为新的主键。