Страницы

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

суббота, 14 декабря 2019 г.

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

#mongodb #aggregation_framework #mongodb_query


Необходимо обновить одним запросом несколько данных. Вот пример запроса:

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 },
    /* Тут был элемент массива */
  ]
}

    


Ответы

Ответ 1



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

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

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