Update in forEach on mongodb shell Update in forEach on mongodb shell mongodb mongodb

Update in forEach on mongodb shell


To get what you want you will need a few things:

t.forEach(function( aRow ) {    var newFields = [];    aRow.fields.forEach( function( aField ){        var newItems = [];        aField.items.forEach( function( item ){            var aNewItem = { item: parseInt(item), ref: 0 };            newItems.push( aNewItem );        } );        newFields.push({ _id: aField._id, items: newItems });    } )    aTable.update(        { _id: aRow._id },         { "$set": { "fields": newFields } }    );});

So basically you need to "re-construct" your arrays before updating


You can make changes directly in the whole object and then save it. Try the following snippet

db.aTable.find().forEach(function (itemWrapper){    itemWrapper.fields.forEach(function(field){        var items = field.items;        var newItems = [];        items.forEach(function(item){          var t = {'item':item,'key':0}          newItems.push(t);              })        field.items = newItems;    })    db.aTable.save(itemWrapper)})

What I am doing is iterating over all items and making a new array with {item : 1 , key:0} and then setting it back to items array in field object.

This is the output after update :

{    "_id" : ObjectId("5332a192ece4ce8362c7a553"),    "title" : "record 1",    "fields" : [         {            "_id" : 1,            "items" : [                 {                    "item" : 1,                    "key" : 0                }            ]        },         {            "_id" : 2,            "items" : [                 {                    "item" : 2,                    "key" : 0                },                 {                    "item" : 3,                    "key" : 0                },                 {                    "item" : 4,                    "key" : 0                }            ]        },         {            "_id" : 3,            "items" : [                 {                    "item" : 5,                    "key" : 0                }            ]        }    ]}/* 1 */{    "_id" : ObjectId("5332a192ece4ce8362c7a554"),    "title" : "record 2",    "fields" : [         {            "_id" : 4,            "items" : [                 {                    "item" : 7,                    "key" : 0                },                 {                    "item" : 8,                    "key" : 0                },                 {                    "item" : 9,                    "key" : 0                },                 {                    "item" : 10,                    "key" : 0                }            ]        },         {            "_id" : 5,            "items" : []        },         {            "_id" : 6,            "items" : [                 {                    "item" : 11,                    "key" : 0                },                 {                    "item" : 12,                    "key" : 0                }            ]        }    ]}


Starting Mongo 4.2, db.collection.update() can accept an aggregation pipeline, finally allowing the update of a field based on its current value, and thus using a query instead of javascript:

// {//   title: "record 1",//   fields: [//     { _id: 1, items: [1] },//     { _id: 2, items: [2, 3, 4] },//     { _id: 3, items: [5] }//   ]// }db.collection.update(  {},  [{ $set: {       fields: { $map: {         input: "$fields",         as: "x",         in: {           _id: "$$x._id",           items: { $map: {             input: "$$x.items",             as: "y",             in: { item: "$$y", key: 0 }           }}         }       }}  }}],  { multi: true })// {//   title: "record 1",//   fields: [//     { _id: 1, items: [ { item: 1, key: 0 } ] },//     { _id: 2, items: [ { item: 2, key: 0 }, { item: 3, key: 0 }, { item: 4, key: 0 } ] },//     { _id: 3, items: [ { item: 5, key: 0 } ] }//   ]// }
  • The first part {} is the match query, filtering which documents to update (in this case all documents).

  • The second part [{ $set: { fields: { $map: { ... } } }] is the update aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline):

    • $set is a new aggregation operator which in this case replaces the field's value.
    • Then (if we go passed the boilerplate) we're simply $mapping the two nested arrays.
    • More specifically, the second map transformation replaces [1, 2] by [{ item: 1, key: 0 }, { item: 2, key: 0 }].
  • Don't forget { multi: true }, otherwise only the first matching document will be updated.