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):- Don't forget
{ multi: true }
, otherwise only the first matching document will be updated.