Mongodb:匹配数组中的元素并更新



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

现在,我必须使用用于聚合的元素的聚合对象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键。显然,该字段存在于您所引用的所有文档中,并且应该将其保留为新的主键。

相关内容

  • 没有找到相关文章

最新更新