MongoDB использует $ cond с обновлением ($ in c) - PullRequest
1 голос
/ 21 апреля 2020

Есть ли способ использовать $ cond вместе с ($ set, $ in c, ...) операторами в обновлении? (MongoDB 4.2) Я хочу обновить поле в моем документе на $ in c с помощью «myDataInt», если условие выполняется, в противном случае оно остается таким, как оно есть:

db.mycoll.update(
    {"_id" : "5e9e5da03da783817d231dc4"},
    {"$inc" : {
       "my_data_sum" : {
           "$cond" : [
               {
                  "$ne" : ["snapshot_time", new_snapshot_time)]
               },myDataInt, 0]
           ]
       }
    },
    {upsert=True, multi=False}
)

Однако это дает ошибка в pymon go:

raise WriteError(error.get("errmsg"), error.get("code"), error)
pymongo.errors.WriteError: The dollar ($) prefixed field '$cond' in 'my_data_sum.$cond' is not valid for storage.

Любая идея, чтобы избежать использования find () перед обновлением в этом случае?


Обновление:

Если я использую подход, о котором упоминал Джо, в PyMon будет выдано исключение go (v3.10.1) из-за использования 'list' в качестве параметра в update_many () вместо 'dict':

from pymongo import MongoClient

db = MongoClient()['mydb']

db.mycoll.update_many(
    {"_id" : "5e9e5da03da783817d231dc4"},
    [{"$set" : {
       "my_data_sum" : {
           "$sum": [
               "$my_data_sum",
               {"$cond" : [
                   {"$ne" : ["snapshot_time", new_snapshot_time]},
                   myDataInt, 
                   0
               ]}
           ]
       }
    }}],

    upsert:true
)


Это заканчивается с этой ошибкой:

  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 1076, in update_many session=session),
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 856, in _update_retryable _update, session)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/mongo_client.py", line 1491, in _retryable_write return self._retry_with_session(retryable, func, s, None)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/mongo_client.py", line 1384, in _retry_with_session return func(session, sock_info, retryable)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 852, in _update retryable_write=retryable_write)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 823, in _update _check_write_command_response(result)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/helpers.py", line 221, in _check_write_command_response _raise_last_write_error(write_errors)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/helpers.py", line 203, in _raise_last_write_error raise WriteError(error.get("errmsg"), error.get("code"), error)
pymongo.errors.WriteError: Modifiers operate on fields but we found type array instead. For example: {$mod: {<field>: ...}} not {$set: [ { $set: { my_data_sum: { $sum: [ "$my_data_sum", { $cond: [ { $ne: [ "$snapshot_time", 1586910283 ] }, 1073741824, 0 ] } ] } } } ]}

Ответы [ 2 ]

0 голосов
/ 22 апреля 2020

Потратив некоторое время и поиск в Интернете, я понял, что методы update_many(), update_one() и update() объекта Collection в PyMon go не принимают список типов в качестве параметров для поддержки новой функции конвейера агрегации. операции обновления в MongoDB 4.2+. (По крайней мере, эта опция пока недоступна в PyMon go v3.10.)
Однако, похоже, я мог бы использовать метод command объекта Database в PyMon go, который является экземпляром ( MongoDB runCommand ) и у меня все заработало:

from pymongo import MongoClient

db = MongoClient()['mydb']

result = db.command(
    {
        "update" : "mycoll",
        "updates" : [{
            "q" : {"_id" : "5e9e5da03da783817d231dc4"},
            "u" : [
                {"$set" : {
                   "my_data_sum" : {
                       "$sum": [
                           "$my_data_sum",
                           {"$cond" : [
                               {"$ne" : ["snapshot_time", new_snapshot_time]},
                               myDataInt,
                               0
                           ]}
                       ]
                   }
                }}
            ],
            "upsert" : True,
            "multi" : True
        }],
        "ordered": False
    }
)


Метод command объекта Databse получает объект dict всех необходимых команд в качестве первого аргумента, а затем список конвейера агрегации может быть включен в объект dict (q является обновлением, а u определяет поля, подлежащие обновлению).
result - это словарь сообщения Ack от MongoDB, которое содержит 'nModified' , 'upserted' и 'writeErrors' .

0 голосов
/ 21 апреля 2020

Если вы используете MongoDB 4.2, вы можете использовать агрегирующие операторы с обновлениями. $inc не является оператором агрегирования, но $sum является. Чтобы указать конвейер, передайте массив в качестве второго аргумента update:

db.coll.update(
    {"_id" : "5e9e5da03da783817d231dc4"},
    [{"$set" : {
       "my_data_sum" : {
           "$sum": [
               "$my_data_sum",
               {"$cond" : [
                   {"$ne" : ["snapshot_time", new_snapshot_time]},
                   myDataInt, 
                   0
               ]}
           ]
       }
    }}],
    {upsert:true, multi:false}
)
...