想要在mongodb中更新二级数组对象

时间:2016-02-26 09:34:31

标签: mongodb mongoose

以下是我的一个收集回复,请不要更新以下收集的库存值。

{
    "_id": ObjectId(),
    "sku": "V4696-DR-V33",
    "options": [
        {
            "sku": "8903689984338",
            "stores": [
                {
                    "code": "AND1",
                    "zipcode": "110070",
                    "id" : 101010,
                    "inventory": 12
                },
                {
                    "code": "AND2",
                    "zipcode": "201010",
                    "id" : 101010,
                    "inventory": 10
                }
            ],
            "price": 2199,
            "_id": ObjectId(),
            "size": "14"
        },
        {
            "sku": "1742564789",
            "stores": [
                {
                    "code": "AND1",
                    "zipcode": "110070",
                    "id" : 101010,
                    "inventory": 21
                },
                {
                    "code": "AND2",
                    "zipcode": "201010",
                    "id" : 101010,
                    "inventory": 20
                }
            ],
            "price": 2199,
            "_id": ObjectId(),
            "size": "16"
        },
    ]
}

想要将所有库存值更新为0那么我该怎么办..? 想要任何简单或单个mongo查询来更新我的所有文档..

1 个答案:

答案 0 :(得分:1)

原子更新无法实现,因为要更新的字段嵌入在嵌套结构中,如果使用使用此类位置运算符标识数组元素的单个更新操作,positional $ update operator将无法访问该嵌套结构位置。在http://jira.mongodb.org/browse/SERVER-1243

,这有一个难题

作为一种解决方法,您需要使用游标遍历集合,并为游标中的每个文档收集有关库存字段的索引位置的数据。然后,您将在循环中使用此数据作为更新操作参数,以正确识别要更新的所需字段。

如果您的集合不那么庞大,可以使用游标的 forEach() 方法实现上述直觉,以进行迭代并获取所涉及的所有数组的索引数据。以下演示了针对小型数据集的这种方法(假设您的集合名为inventory):

db.inventory.find({"options.stores.inventory": { "$exists": true, "$ne": 0 }}).forEach(function(doc){ 
    var options = doc.options; 
    for (var optionIndex = 0; optionIndex < options.length; optionIndex++){ 
        var stores = options[optionIndex].stores
        for (var storeIndex = 0; storeIndex < stores.length; storeIndex++){ 
            var updateOperatorDocument = {};
            updateOperatorDocument["options."+optionIndex+".stores."+storeIndex+".inventory"] = 0
            db.inventory.update(
                { "_id": doc._id },
                { "$set": updateOperatorDocument }
            );
        }        
    } 
});

为了提高性能,尤其是在处理大型集合时,请利用 Bulk() API有效地批量更新集合,因为您将批量发送操作到服务器(例如,说批量大小为500)。这样可以提供更好的性能,因为您不会向服务器发送每个请求,而是每500个请求中只发送一次请求,从而使您的更新更加高效和快捷。

以下示例演示如何使用MongoDB版本>= 2.6< 3.2中提供的 Bulk() API。

var bulkUpdateOps = db.inventory.initializeUnOrderedBulkOp(),   
    counter = 0;

db.inventory.find({"options.stores.inventory": { "$exists": true, "$ne": 0 }}).forEach(function(doc){ 
    var options = doc.options; 
    for (var optionIndex = 0; optionIndex < options.length; optionIndex++){ 
        var stores = options[optionIndex].stores
        for (var storeIndex = 0; storeIndex < stores.length; storeIndex++){ 
            var updateOperatorDocument = {};
            updateOperatorDocument["options."+optionIndex+".stores."+storeIndex+".inventory"] = 0
            bulkUpdateOps.find({ "_id": doc._id }).update({ "$set": updateOperatorDocument })
        }        
    }     
    counter++;  // increment counter for batch limit
    if (counter % 500 == 0) { 
        // execute the bulk update operation in batches of 500
        bulkUpdateOps.execute(); 
        // Re-initialize the bulk update operations object
        bulkUpdateOps = db.inventory.initializeUnOrderedBulkOp();
    } 
})

// Clean up remaining operation in the queue
if (counter % 500 != 0) { bulkUpdateOps.execute(); }

下一个示例适用于自deprecated Bulk() API以来的新MongoDB版本3.2,并使用 {{3}提供了一套更新的api }

它使用与上面相同的游标,但使用相同的 bulkWrite() 游标方法创建具有批量操作的数组,以将每个批量写入文档推送到数组:

var cursor = db.inventory.find({"options.stores.inventory": { "$exists": true, "$ne": 0 }}),
    bulkUpdateOps = [];

cursor.forEach(function(doc){ 
    var options = doc.options; 
    for (var optionIndex = 0; optionIndex < options.length; optionIndex++){ 
        var stores = options[optionIndex].stores
        for (var storeIndex = 0; storeIndex < stores.length; storeIndex++){ 
            var updateOperatorDocument = {};
            updateOperatorDocument["options."+optionIndex+".stores."+storeIndex+".inventory"] = 0
            bulkUpdateOps.push({ 
                "updateOne": {
                    "filter": { "_id": doc._id },
                    "update": { "$set": updateOperatorDocument }
                 }
            });
        }        
    }
});         

db.inventory.bulkWrite(bulkUpdateOps);

为样本数据撰写结果

{
    "acknowledged" : true,
    "deletedCount" : 0,
    "insertedCount" : 0,
    "matchedCount" : 4,
    "upsertedCount" : 0,
    "insertedIds" : {},
    "upsertedIds" : {}
}