Question:
It is necessary to update several data with one request. Here's an example request:
db.coll.update(
{ article: 100500 },
{
$set: { a: 555 },
$pull: { arr: { t: { $lt: 20 } } }
}
);
And here's an example of the document itself:
{
article: 100500,
a: 400,
arr: [
{ t: 30, b: 12, n: 90 },
{ t: 10, b: 16, n: 60 }
]
}
My request:
- Updates the value of
a
to555
. - Removes all elements of the
arr
array wheret < 20
.
The crux of the question: It is necessary to update the values of b
in the arr
. That is, wherever n == 90
, the value of b
must be changed to 777
. How can this query be supplemented to "kill 3 birds with one stone"?
As a result, you should get the following document:
{
article: 100500,
a: 555, /* Тут было: 400 */
arr: [
{ t: 30, b: 777, n: 90 },
/* Тут был элемент массива */
]
}
Answer:
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 be aware 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; making things more difficult.
The best way to do this is using Bulk Operations .
Solution for MongoDB version 3.2 or newer:
MongoDB 3.2 deprecated Bulk()
and related methods. You need to use the .bulkWrite()
method
Here we have two options:
-
You need to use aggregation to reduce the number of documents that need to be updated. here only one step is needed in the chain:
$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()
methoddb.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 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(); }
Result
{
"_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 }
]
}