更新另一个集合的匹配记录?

时间:2014-06-30 23:59:53

标签: javascript mongodb aggregation-framework

有人可以帮我更新基于另一个的收藏吗?我有一个像这样的皮卡系列。

{
    "_id": {
        "$oid": "53a46be700b94521574b6f75"
    },
    "created": {
        "$date": 1403236800000
    },
    "receivers": [
        {
            "model": "somemodel1",
            "serial": "someserial1",
            "access": "someaccess1"
        },
        {
            "model": "somemodel2",
            "serial": "someserial2",
            "access": "someaccess2"
        },
        {
            "model": "somemodel3",
            "serial": "someserial3",
            "access": "someaccess3"
        }
    ],
    "__v": 0
}

我想迭代接收器数组并搜索另一个集合中的每个访问,如果找到则添加它所在的活动。

这是我想要搜索的工作人员集合。

{
    "_id": {
        "$oid": "53af72481b2aeade0b46d025"
    },
    "activityNumber": "someactivity",
    "date": "06/28/2014",
    "lines": [
        {
            "Line #": "1",
            "Access Card #": "someaccess1"
        },
        {
             "Line #": "2",
            "Access Card #": "someaccess2"
        },
        {
             "Line #": "3",
            "Access Card #": "someacess3"
        }
    ],
}

这就是我想要的结果。

{
        "_id": {
            "$oid": "53a46be700b94521574b6f75"
        },
        "created": {
            "$date": 1403236800000
        },
        "receivers": [
            {
                "model": "somemodel1",
                "serial": "someserial1",
                "access": "someaccess1",
                "activityNumber": "someactivity"
            },
            {
                "model": "somemodel2",
                "serial": "someserial2",
                "access": "someaccess2",
                "activityNumber": "someactivity"
            },
            {
                "model": "somemodel3",
                "serial": "someserial3",
                "access": "someaccess3",
                "activityNumber": "someactivity"
            }
        ],
        "__v": 0
    }

我创建了一个包含拾取器所有访问权限的数组。

var prodValues = db.pickups.aggregate([

    { "$unwind":"$receivers" },

    { "$group": {
        "_id": null,
        "products": { "$addToSet": "$receivers.access"}
    }}
])

我可以轻松地遍历数组并搜索工作人员收集并返回其使用的活动。但我不确定如何在找到时执行查找并更新拾取集合。

db.workorders.find({ "lines.Access Card #": { "$in": prodValues.result[0].products }},{activityNumber:1})

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

真的,我会以完全相反的顺序循环这个,因为它应该更有效:

var result = db.workorders.aggregate([
    { "$project": { 
        "activityNumber": 1,
        "access": "$lines.Access Card #",
    }}
]).result;

result.forEach(function(res) {

    res.access.forEach(function(acc) {
        db.pickups.update(
            { "receivers.access": acc },
            { "$set": { "receivers.$.activityNumber": res.activityNumber } }
        );
    });

});

使用MongDB 2.6,您可以通过聚合输出上的游标和批量操作API的使用来清理它:

var batch = db.pickups.initializeOrderedBulkOp();
var counter = 0;

db.workorders.aggregate([
    { "$project": { 
        "activityNumber": 1,
        "access": "$lines.Access Card #",
    }}
]).forEach(function(res) {
    res.access.forEach(function(acc) {
        batch.find({ "receivers.access": acc }).updateOne(
            { "$set": { "receivers.$.activityNumber": res.activityNumber } }
        );
    });

    if ( counter % 500 == 0 ) {
        batch.execute();
        var batch = db.pickups.initializeOrderedBulkOp();
        counter = 0;
    }

});

if ( counter > 0 )
    batch.execute();

无论哪种方式,您基本上都匹配文档和数组在第一个聚合查询和当前行返回的“access”值上的位置。这允许更新指定位置的相关信息。

MongoDB 2.6的改进是你没有把所有结果从“workoders”集合中拉出来作为一个数组存储到内存中,所以只有每个文档都从游标结果中拉入。

批量操作操作将“更新”存储在可管理的块中,这些块应低于16MB BSON限制,然后在这些块中发送,而不是单独更新。驱动程序实现应该处理大部分内容,但为了安全起见,还添加了一些“自我管理”。