mongodb:匹配数组中的元素并进行更新

时间:2014-06-30 09:03:45

标签: javascript mongodb aggregation-framework updates

基本上,我已经完成聚合以获得构成总数的对象的总数和列表。

现在,我必须使用聚合对象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

有没有更好的方法来做到这一点。

1 个答案:

答案 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键。显然,该字段存在于您采购的所有文档中,并且应该将其保留为新的主键。