在Mongodb子文档数组中,有任何方法可以在每个子库中添加新字段

时间:2015-04-23 12:19:52

标签: arrays mongodb subdocument

假设我有一个像

这样的文件
{
    "_id" : 5,
    "rows": [
        { "id" : "aab", "value":100},
        { "id" : "aac", "value":400},
        { "id" : "abc", "value":200},
        { "id" : "xyz", "value":300}
    ]
}

我需要在每个子文档" status"中添加一个新密钥。 :1 ,结果应该看起来像

{
    "_id" : 5,
    "rows": [
        { "id" : "aab", "value":100, "status":1},
        { "id" : "aac", "value":400, "status":1},
        { "id" : "abc", "value":200, "status":1},
        { "id" : "xyz", "value":300, "status":1}
    ]
}

如何通过单一更新查询来完成此操作?

1 个答案:

答案 0 :(得分:1)

Mongo positional operator $elemMatch有问题;

  

$运算符可以更新匹配使用$ elemMatch()运算符指定的多个查询条件的第一个数组元素。

因此,使用mongo查询的情况下,您应该只更新特定的匹配条件。如果您在匹配中设置rows.aac,则会在status:1数组中添加row.aac,请按以下方式检查查询:

db.collectionName.update({
  "_id": 5,
  "rows": {
    "$elemMatch": {
      "id": "abc"
    }
  }
}, {
  $set: {
    "rows.$.status": 1
  }
}, true, false) // here you insert new field so upsert true

mongo update显示upsertmulti的工作原理。

但是您仍然想要更新所有文档,那么您应该使用一些programming code或一些script。下面的代码使用cursor forEach更新所有数据:

db.collectionName.find().forEach(function(data) {
  for (var ii = 0; ii < data.rows.length; ii++) {
    db.collectionName.update({
      "_id": data._id,
      "rows.id": data.rows[ii].id
    }, {
      "$set": {
        "rows.$.status": 1
      }
    }, true, false);
  }
})

如果您的文档尺寸更大,那么使用下面代码mongo bulk update的更好方法会显示如何使用mongo bulk进行更新:

var bulk = db.collectionName.initializeOrderedBulkOp();
var counter = 0;
db.collectionName.find().forEach(function(data) {
  for (var ii = 0; ii < data.rows.length; ii++) {

    var updatedDocument = {
      "$set": {}
    };

    var setStatus = "rows." + ii + ".status";
    updatedDocument["$set"][setStatus] = 101;
    // queue the update
    bulk.find({
      "_id": data._id
    }).update(updatedDocument);
    counter++;
    //  re-initialize every 1000 update statements
    if (counter % 1000 == 0) {
      bulk.execute();
      bulk = db.collectionName.initializeOrderedBulkOp();
    }
  }

});
// Add the rest in the queue
if (counter % 1000 != 0)
  bulk.execute();