使用更新

时间:2016-03-21 08:16:48

标签: mongodb mongodb-query

我有一些文件,如

doc:{
    "_id":6,
    item1:"something"
    item2:[
    {
        subitem1:value1,
        subitem2:value2
    },
    {
        subitem1:value3,
        subitem2:value4
    }
    ]
}

我想插入一个包含另外两个数据的字段,然后删除它们以获得此

doc:{
    "_id":6,
    item1:"something"
    item2:[
    {
        subitem:{field:value1,field2:value2}
    },
    {
        subitem:{field:value3,field2:value4}
    }
    ]
}

我必须使用1个脚本更新集合的所有文档。 我已经尝试了几个东西,比如$ set,$ push但没有任何效果(执行时没有错误)

我的上一个剧本是

db.docs.find({}).update.forEach(
function(doc){
    doc.item2.forEach(
        function(item){
            { $set : {item.subitem = {field:item.subitem1,field2:item.subitem2}}}
        }
    )
    db.docs.save(doc);
}
,false,true)

这不会产生错误但不会执行任何操作。 我甚至没有找到如何删除字段。 请帮帮我!

1 个答案:

答案 0 :(得分:1)

您应该使用.bulkWrite()进行循环以提交更新。这里要注意的主要是你实际上正在迭代的东西,它是集合项以及要转换的目标数组的成员。

要么用整个阵列替换它,要么替换它:

var ops = [];

db.docs.find({ 
    "item2": {
        "$elemMatch": { 
            "subitem1": { "$exists": true },
            "subitem2": { "$exists": true }
        }
    }
}).forEach(function(doc) {
    doc.item2 = doc.item2.map(function(el) {
        return { "subitem": { "field1": el.subitem1, "field2": el.subitem2 } };            
    });
    ops.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": { "$set": { "item2": doc.item2 } }
        }
    });

    // Test outside array looping
    if ( ops.length == 1000 ) {
        db.docs.bulkWrite(ops);
        ops = []
    }
});

if ( ops.length > 0 )
    db.docs.bulkWrite(ops);

或者最好使用positional matches作为更新:

var ops = [];

db.docs.find({ 
    "item2": {
        "$elemMatch": { 
            "subitem1": { "$exists": true },
            "subitem2": { "$exists": true }
        }
    }
}).forEach(function(doc) {
    doc.item2.forEach(function(item) {
        var updoc = { "subitem": { "field1": item.subitem1, "field2": item.subitem2 } };
        ops.push({
            "updateOne": {
                "filter": { 
                    "_id": doc._id,
                    "item2": { 
                        "$elemMatch": {
                            "subitem1": item.subitem1,
                            "subitem2": item.subitem2
                        }
                    }
                },
                "update": { "$set": { "item2.$": updoc  } }
            }
        });

        // Test inside the array looping
        if ( ops.length == 1000 ) {
            db.docs.bulkWrite(ops);
            ops = []
        }
    });

});

if ( ops.length > 0 )
    db.docs.bulkWrite(ops);

后一种情况更好的原因是每个元素的写入实际上是原子的,因此在高容量环境中,您不会从其他进程获得冲突的写入。

这是转换当前数组内容的快速而安全的方法。第一种方式会运行得更快,但我真的不会在实时系统上推荐它。第二个仍然会非常快,但由于它在操作中一次更新一个数组元素,因此还有更多工作要做。

在这两种情况下,与服务器的实际“有线通信”仅发生在千分之一的操作中,因此这消除了发送请求和等待每次更新响应的开销。