猫鼬多重更新

时间:2016-02-04 19:01:30

标签: node.js mongodb express mongoose

我想要使用不同的值更新多个文档。

我的数据库看起来像这样。

[
    {
        "_id": 1,
        "value": 50
    },
    {
        "_id": 2,
        "value": 100
    }
]

此查询返回错误,因为我在$ set中传递数组而不是对象。

    Model.update({_id: {$in: ids}}, {$set: ids.value}, {multi: true};

我希望我的数据库看起来像这样

[
        {
            "_id": 1,
            "value": 4
        },
        {
            "_id": 2,
            "value": 27
        }
    ]

3 个答案:

答案 0 :(得分:6)

假设您有一组对象要在集合中更新匹配的ID,如

var soldItems = [
        {
            "_id": 1,
            "value": 4
        },
        {
            "_id": 2,
            "value": 27
        }
    ];

然后你可以使用数组上的 forEach() 方法来迭代它并更新你的集合:

soldItems.forEach(function(item)){
    Model.update({"_id": item._id}, {"$set": {"value": item.value }}, callback);
});

或使用承诺

var updates = [];
soldItems.forEach(function(item)){
    var updatePromise = Model.update({"_id": item._id}, {"$set": {"value": item.value }});
    updates.push(updatePromise);
});

Promise.all(updates).then(function(results){
    console.log(results);
});

或使用 map()

var updates = soldItems.map(function(item)){
    return Model.update({"_id": item._id}, {"$set": {"value": item.value }});       
});

Promise.all(updates).then(function(results){
    console.log(results);
}); 

对于较大的阵列,您可以利用批量写入API来获得更好的性能。对于支持>=4.3.0的Mongoose版本MongoDB Server 3.2.x, 您可以使用 bulkWrite() 进行更新。以下示例说明了如何解决此问题:

var bulkUpdateCallback = function(err, r){
    console.log(r.matchedCount);
    console.log(r.modifiedCount);
}
// Initialise the bulk operations array
var bulkOps = soldItems.map(function (item) { 
    return { 
        "updateOne": { 
            "filter": { "_id": item._id } ,              
            "update": { "$set": { "value": item.value } } 
        }         
    }    
});

// Get the underlying collection via the native node.js driver collection object
Model.collection.bulkWrite(bulkOps, { "ordered": true, w: 1 }, bulkUpdateCallback);

对于支持MongoDB服务器~3.8.8, ~3.8.22, 4.x的Mongoose版本>=2.6.x,您可以使用 Bulk API ,如下所示

var bulk = Model.collection.initializeOrderedBulkOp(),
    counter = 0;

soldItems.forEach(function(item) {
    bulk.find({ "_id": item._id }).updateOne({ 
        "$set": { "value": item.value }
    });

    counter++;
    if (counter % 500 == 0) {
        bulk.execute(function(err, r) {
           // do something with the result
           bulk = Model.collection.initializeOrderedBulkOp();
           counter = 0;
        });
    }
});

// Catch any docs in the queue under or over the 500's
if (counter > 0) {
    bulk.execute(function(err,result) {
       // do something with the result here
    });
}

答案 1 :(得分:3)

首先,您的update()查询不正确..

请参阅此here

的文档
  

Model.update(conditions, update, options, callback);

假设您当前的数据库模型包含这样的文档(正如您所描述的那样):

[
    {
        "_id": 1,
        "value": 50
    },
    {
        "_id": 2,
        "value": 100
   }
];

并且您在下面的数组中包含要使用当前db的文档修改的对象(即文档),如下所示:

idsArray: [
    {
        "_id": 1,
        "value": 4
    },
    {
        "_id": 2,
        "value": 27
    }
];

根据我对mongodb& amp ;;的经验mongoose,我不认为你可以使用单行查询更新所有文档(这是你想要做的)..(P.S。我不知道这个,所以我不确定这个..)

但为了使你的代码有效,你将会做这样的事情:

想法:遍历文档中的每个文档,即idsArray并在其上调用update()..

所以,这是代码:

idsArray.forEach(function(obj) {
    Model.update({_id: obj._id}, {$set: {value: obj.value}});
});

在上面的代码中,我假设你在db docs中有_id个值,因为它们在上面写了(即"_id": 1)..但是如果它们是这样的{{1} }

"_id": ObjectId('1')

然后您需要在update()查询中将[ { "_id": ObjectId('1'), "value": 50 }, ..... ..... ] 转换为_id。 所以你会这样做。

ObjectId(obj._id)

P.S。在前进之前确认一下(即var ObjectId = require('mongodb').ObjectID; idsArray.forEach(function(obj) { Model.update({_id: ObjectId(obj._id)}, {$set: {value: obj.value}}); }); )..

希望这有帮助。

干杯,

答案 2 :(得分:1)

多次更新只能用于将多个文档更新为相同的值,或者使用相同的update operation更新所有文档。

如果要更新为不同的值,则必须使用多个更新语句。

相关问题