Удалить полный документ или элемент из массива на основе условия - PullRequest
0 голосов
/ 14 мая 2018

Документы моей коллекции:

    {
      "_id" : 1,
      "fruits" : [ {"name":"pears"},
                   {"name":"grapes"},
                  {"name":"bananas"} ],
    }
    {
      "_id" : 2,
      "fruits" : [ {"name":"bananas"} ],
    }

Мне нужно удалить весь документ, если фрукты содержат только "бананы", или удалить фрукты "бананы" только тогда, когда в фруктах содержится более одного фрукта.массив.

Моя последняя коллекция после выполнения обязательного запроса должна быть:

{
  "_id" : 1,
  "fruits" : [ {"name":"pears"},
                   {"name":"grapes"}],
}

В настоящее время я использую два запроса, чтобы сделать это:

db.collection.remove({'fruits':{$size:1, $elemMatch:{'name': 'bananas'} }}) [this will remove the document when only one fruit present]

и

db.collection.update({},{$pull:{'fruits':{'name':'bananas'}}},{multi: true}) [this will remove the entry 'bananas' from the array]

Есть ли способ объединить их в один запрос ?

РЕДАКТИРОВАТЬ: Окончательный вариант

- Я полагаю, что для выполнения вышеуказанных задач не существует "одного запроса", поскольку намерения сильно отличаются от обоих действий.

- Лучшее, что можно выполнить: объединить действия взапрос bulk_write, сохраняющий данные ввода-вывода в сети (как указано в ответе Нила).Это считается более полезным, когда у вас есть несколько таких действий.Кроме того, bulk_write может обеспечить функцию блокировки в том смысле, что режим «упорядоченного» режима bulk_write делает действия последовательными, прерывая и останавливая выполнение в случае ошибки.

Следовательно, то параметр bulk_write более полезен, когда выполняемые действиядолжны быть последовательными.Что-то вроде «цепочки» в JS.Существует также возможность выполнять неупорядоченные объемные записи.

Кроме того, действия, указанные в массовой записи, работают с collection level as individual actions.

Ответы [ 2 ]

0 голосов
/ 14 мая 2018
db.users.aggregate(
 [{
        $project: {
           data: {
                $filter: {
                    input: "$fruits",
                    as: "filterData",
                    cond: { $ne: [ "$$filterData.name", 'bananas' ] }
                  }
                }
        }
    },
     {
        $unwind: {
            path : "$data",
            preserveNullAndEmptyArrays : false 
        }
    },
     {
        $group: {
        _id:"$_id",
        data: { $addToSet: "$data" }
        }
    },
])

Я думаю, что приведенный выше запрос даст вам идеальные результаты

0 голосов
/ 14 мая 2018

Вы в основном хотите, чтобы bulk_write() здесь, чтобы сделать их обоих. Также используйте $exists, чтобы убедиться, что есть только один элемент:

from pymongo import UpdateMany, DeleteMany

db.collection.bulk_write(
  [
   UpdateMany(
    { "fruits.1": { "$exists": True }, "fruits.name": "bananas" },
    { "$pull":{ 
      'fruits': { 'name':'bananas' }
    }}
   ),
   DeleteMany(
    { "fruits.1": { "$exists": False }, "fruits.name": "bananas" }
   )
  ],
  ordered=False
)

Вам действительно не нужно $elemMatch для условия "один", и вы должны использовать update_many(), и в этом случае UpdateMany() вместо { "multi": true }. И этот вариант отличается от "пимонго" в любом случае. Тогда, конечно, есть delete_many() или DeleteMany() для «массового» контекста.

Массовые операции отправляют один запрос с одним ответом, что лучше, чем отправка нескольких запросов. Также «обновление» и «удаление» - это две разные вещи, но один запрос может комбинироваться так же, как это.

Оператор $size действителен, но $exists может применяться к «диапазону», где $size не может, так что обычно это немного более гибкий.

То есть как $exists пример диапазона

# Array between 2 and 4 elements
db.collection.update_many(
  { 
    "fruits.1": { "$exists": True },
    "fruits.4": { "$exists": False }, 
    "fruits.name": "bananas"
  },
  { "$pull":{ 
    'fruits': { 'name':'bananas' }
  }}
)

И, конечно, в данном контексте вы на самом деле хотите узнать разницу между другими возможными вещами в массиве и теми, у кого "только" один "банан".

Здесь ordered=False на самом деле относится к двум различным способам обработки запросов «массовой записи»

  • Упорядочено - Где True (что является «значением по умолчанию»), тогда операции выполняются в «последовательном порядке», как они появляются в массиве операций, отправленных с «массовой записью». ». Если здесь происходит какая-либо ошибка, то пакет останавливает выполнение в точке ошибки и возвращает исключение.

  • UnOrdered - где False операции выполняются "параллельно" в рамках разумных ограничений на сервере. Если возникает какая-либо ошибка, все еще возникает исключение, однако это не останавливает выполнение других операций в рамках «массовой записи». Любые ошибки возвращаются с «индексом массива» из списка, предоставленного команде, операция которой вызвала ошибку.

Эта опция может использоваться для «настройки» желаемого поведения, в частности, для сообщения об ошибках и продолжения, а также обеспечивает степень «параллелизма» к выполнению, когда «последовательный» фактически не требуется для операций. Поскольку эти два утверждения на самом деле не зависят от одного или другого и фактически все равно будут выбирать разные документы, тогда ordered=False, вероятно, является лучшим вариантом с точки зрения эффективности.

...