Search code examples
arraysmongodbsubdocument

In Mongodb subdocument array is there any way to add a new field in each subcoument


Suppose i have a document like

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

and i need to add a new key in each sub document "status" : 1 and result should be look like

{
    "_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}
    ]
}

How can i do this by single update query?


Solution

  • Mongo positional operator with $elemMatch having problem;

    The $ operator can update the first array element that matches multiple query criteria specified with the $elemMatch() operator.

    So this case using mongo query you should update only specific matching criteria. If you set rows.aac in match then you will add status:1 in row.aac array, check query as below :

    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 showing how upsert and multi works.

    But still you want to updated all documents then you should use some programming code or some script. Below code update all data using 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);
      }
    })
    

    If your documents size more then better way to use mongo bulk update below code shows how to updated using 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();