2

有没有办法在更新中使用 $cond 和 ($set, $inc, ...) 运算符?(MongoDB 4.2)如果条件满足,我想通过 $inc 用“myDataInt”更新文档中的字段,否则保持原样:

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

但是,这会在 pymongo 中出现错误:

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() 吗?


更新:

如果我使用 Joe 提到的方法,由于在 update_many() 中使用“list”而不是“dict”作为参数,PyMongo (v3.10.1) 将引发异常:

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 ] } ] } } } ]}
4

3 回答 3

0

如果您使用的是 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}
)
于 2020-04-21T18:24:55.407 回答
0

经过一段时间的网上搜索,我发现 PyMongo 中 Collection 对象的update_many()update_one()update()方法不接受类型列表作为参数,以支持 MongoDB 4.2+ 中更新操作的新聚合管道特性。(至少这个选项在 PyMongo v3.10 中还没有。)

但是,看起来我可以command在 PyMongo 中使用 Database 对象的方法,它是(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方法获取所有需要的命令的dict对象作为它的第一个参数,然后可以将聚合管道的列表包含在dict对象中(q是更新查询,并u定义了要更新的字段)。

result是来自 MongoDB 的 Ack 消息字典,其中包含'nModified''upserted''writeErrors'

于 2020-04-22T16:46:20.537 回答
0

https://mongoplayground.net/p/1AklFKuhFi6

[
  {
    "id": 1,
    "like": 3
  },
  {
    "id": 2,
    "like": 1
  }
]

让值 = 1,

如果你想增加然后使用

值 = -1 * 值

db.collection.aggregate([
  {
    "$match": {
      "id": 1
    }
  },
  {
    "$set": {
      "count": {
        $cond: {
          if: {
            $gt: [
              "$like",
              0
            ]
          },
          then: {
            "$subtract": [
              "$like",
               value
            ]
          },
          else: 0
        }
      }
    }
  }
])
于 2022-02-10T13:35:25.767 回答