Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 767
P K P Avatar asked Nov 10 '22 15:11

P K P


1 Answers

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();
like image 144
Yogesh Avatar answered Nov 15 '22 06:11

Yogesh