Pymongo执行update_many引用同文档字段赋值未生效如何解决
问题描述
现有结构如下的MongoDB集合:
[ { "_id": 1, "animals": { "goat": 1 } }, { "_id": 2, "animals": { "cow": 1, "horse": 2, "goat": 1 } }, { "_id": 3, "animals": { "horse": 5 } }, { "_id": 4, "animals": { "cow": 1 } } ]
需求是:为所有包含animals.horse字段且该字段值大于0的文档,将animals.goat的值设置为同文档内animals.horse的取值。
在Mongo shell中执行以下语句可以得到预期结果:
db.collection.update( {"animals.horse": { "$gt": 0 }}, [ { "$set": { "animals.goat": "$animals.horse" } } ], { "multi": true } )
预期执行结果如下:
[ { "_id": 1, "animals": { "goat": 1 } }, { "_id": 2, "animals": { "cow": 1, "goat": 2, "horse": 2 } }, { "_id": 3, "animals": { "goat": 5, "horse": 5 } }, { "_id": 4, "animals": { "cow": 1 } } ]
但在pymongo中执行如下update_many语句后,集合数据没有任何修改:
db.collection.update_many( filter = {'animals.horse': {'$gt':0} }, update = [ {'$set': {'animals.goat': '$animals.horse' } } ], upsert = True )
问题原因
你的操作存在两个可能的问题:
- 版本不兼容
- 聚合管道形式的更新操作(update参数传入数组)是MongoDB 4.2版本才新增的特性,如果你的MongoDB服务端版本低于4.2,无法识别该语法,更新不会执行。
- 3.11版本以下的pymongo驱动不支持向
update_many的update参数传入聚合管道列表,会将传入的列表视为无效参数,导致没有执行更新操作。
- 冗余的
upsert=True参数:虽然该参数不会影响已经匹配到的文档更新,但你的需求仅需要更新现有文档,不需要在没有匹配到文档时插入新文档,该参数属于不必要配置。
解决方法
方案一:升级到支持管道更新的版本
首先确认MongoDB服务端版本 >=4.2、pymongo驱动版本 >=3.11,修改代码如下即可:
db.collection.update_many( {'animals.horse': {'$gt':0}}, [{'$set': {'animals.goat': '$animals.horse'}}] )
方案二:兼容旧版本的实现
如果无法升级版本,可以先查询匹配的文档,再逐个更新:
for doc in db.collection.find({'animals.horse': {'$gt':0}}, {'animals.horse': 1}): db.collection.update_one( {'_id': doc['_id']}, {'$set': {'animals.goat': doc['animals']['horse']}} )
内容的提问来源于stack exchange,提问作者C8H10N4O2
相关产品推荐
相关产品推荐

