更新多个文档/将键及其值添加到新阵列中

时间:2014-08-04 17:20:00

标签: javascript mongodb mongodb-query

我有一个名为inventory的集合,其中我有多个文档,每个文档都有每个文档的值

{ "apples": 2 ,"oranges": 3,  "carrots": 5 }
{ "apples": 4, "oranges": 6, "carrots": 9 }

如何在多个文档中更新所有水果到单个数组:

{ "fruits": { "apples":2 ,"oranges":3 }, "carrots": 5 }

1 个答案:

答案 0 :(得分:1)

首先要注意的是,您提供的示例不是数组,而只是具有不同键的“fruits”的子文档。 MongoDB中的“数组”如下所示:

{ "fruits": [{ "apples":2 } , { "orange":3 }], "carrot": 5 }

此外,除了术语“水果”是主观的,因为没有其他标识符你必须指定一个符合水果条件的“列表”,另外要考虑的是MongoDB中没有实际的方法目前在处理更新时参考字段的现有值。

这意味着您需要.find()每个文档检索数据,以便能够使用您想要的那种“重组”。这实质上意味着循环结果,为每个文档执行.update()操作。

MongoDB 2.6及更高版本的Bulk API在这里可以提供一些帮助,其中至少对数据库的“写入”操作可以批量发送,而不是一次发送一次:

var bulk = db.collection.initializeOrderedBulkOp();
var count = 0;

var fruits = ["apples","oranges"];
var unset = {};

fruits.forEach(function(fruit) {
   unset[fruit] = 1;
});


db.collection.find({}).forEach(function(doc) {

   var fields = [];
   fruits.forEach(function(fruit) {
       if ( doc.hasOwnProperty(fruit) ) {
           var subDoc = {};
           subDoc[fruit] = doc[fruit];
           fields.push(subDoc);
       }
   });

   bulk.find({ "_id": doc._id }).updateOne({ 
       "$unset": unset, "$push": { "fruits": { "$each": fields } }
   });
   count++;

   if ( count % 1000 == 0 ) {
       bulk.execute();
       var bulk = db.collection.initializeOrderedBulkOp();
   }

});

if ( count % 1000 != 0 )
    bulk.execute();

这也为$each使用$push修饰符,以便一次添加多个数组条目。可以安全地为文档中不存在的字段调用$unset运算符,因此在构造$push元素数组时,无需检查它们是否存在于文档中。

当然,如果您真的想要一个类似于您提供的示例的文档实际上并不是一个数组,那么您使用$set运算符进行不同的构造:

   var fields = {};
   fruits.forEach(function(fruit) {
       if ( doc.hasOwnProperty(fruit) )
           fields[fruit] = doc[fruit];
   });

   bulk.find({ "_id": doc._id }).updateOne({ 
       "$unset": unset, "$set": { "fruits": fields }
   });

无论是什么情况,您都需要循环现有的集合。没有任何操作允许您“获取”文档中的现有值并“使用它”以便从服务器端角度设置新值。