I assume you have the following documents in your collection.
{ "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 0, "b" : 12, "n" : 90 }, { "t" : 10, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] }
First of all, you should know that it is not possible to update more than one element in an array using the update()
method even with the multi: true
updateMany()
or using the updateMany()
method; and all the logic behind what you are trying to do; make things more difficult.
The best way to do this is using Bulk Operations .
Solution for MongoDB version 3.2 or newer:
MongoDB 3.2 does not recommend Bulk()
and related methods. You need to use the .bulkWrite()
method
Here we have two options:
It is necessary to use aggregation to reduce the number of documents that need to be updated. here only one stage in the chain is needed: $project
where we use the $filter
operator.
let requests = [];
db.collection.aggregate([ { "$project": { "deleteElements": { "$filter": { "input": "$arr", "as": "del", "cond": { "$lt": [ "$$del.t", 12 ] } } }, "updateElements": { "$filter": { "input": "$arr", "as": "upd", "cond": { "$and": [ { "$gte": [ "$$upd.t", 12 ] }, { "$eq": [ "$$upd.n", 90 ] } ] } } } }} ]).forEach(function(document) { document.deleteElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.t }, "update": { "$pull": { "arr": element } } } } ); }); document.updateElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.n }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); }) db.collection.bulkWrite(requests)
Using the .find()
method
db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": { "$lt": 12 }}, "update": { "$pull": { "arr": element } } } } ); }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.n": 90 }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); }) db.collection.bulkWrite(requests);
Solution for MongoDB version 2.6 or newer:
var bulk = db.collection.initializeOrderedBulkOp(); var count = 0; db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.t": { "$lt": 12 } } ).updateOne({ "$pull": { "arr": element } }); count++; }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.n": 90 }).updateOne({ "$set": { "arr.$.b": 777 } }); count++; }); bulk.find( { "_id": document._id } ).updateOne( { "$set": { "a": 555 } } ); count++; if (count % 1000 === 0) { // Выпольнить после 1000 операции bulk.execute(); bulk = db.collection.initializeOrderedBulkOp(); } }) // Очистить очереди if (count > 0) { bulk.execute(); }
To show
{ "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] } { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 555, "arr" : [ ] } { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] }