Страницы

Поиск по вопросам

вторник, 23 октября 2018 г.

Как обновить несколько элементов в массиве?

Необходимо обновить одним запросом несколько данных. Вот пример запроса:
db.coll.update( { article: 100500 }, { $set: { a: 555 }, $pull: { arr: { t: { $lt: 20 } } } } );
А вот пример самого документа:
{ article: 100500, a: 400, arr: [ { t: 30, b: 12, n: 90 }, { t: 10, b: 16, n: 60 } ] }
Мой запрос:
Обновляет значение a на 555 Удаляет все элементы массива arr, где t < 20
Суть вопроса: Надо обновить значения b в маccве arr. То есть, везде где n == 90, значение b надо поменять на 777. Как можно дополнить этот запрос, чтобы "убить сразу 3-х зайцев"?
В итоге должен получиться такой документ:
{ article: 100500, a: 555, /* Тут было: 400 */ arr: [ { t: 30, b: 777, n: 90 }, /* Тут был элемент массива */ ] }


Ответ

Я полагаю, у вас есть следующие документы в вашей коллекции.
{ "_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 } ] }

Прежде всего вы должны знать, что это не возможно, чтобы обновить более одного элемента в массиве используя метод update() даже с опцей multi: true или используя метод updateMany(); и все логики позади, что вы пытаетесь сделать; делать вещи более сложнее.
Лучший способ это делать это используя Bulk Операции
Решение для MongoDB версия 3.2 или новее:
MongoDB 3.2 не рекомендуется Bulk() и связанные с ним методы. Нужно использовать метод .bulkWrite()
Здесь у нас есть два варианта:
Нужно использовать агрегация чтотбы уменшать количество докуменьов которые нужно обновить. здесь в цепочке нужно только один этап: $project где мы используем оператор $filter
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) Используя метод .find()
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);

Решение для MongoDB версии 2.6 или новее:
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(); }

Результать
{ "_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 } ] }

Комментариев нет:

Отправить комментарий