MongoDB中仅更新含images字段的指定post及图片状态
数据库Schema
{ "_id": "365e4101-9dda-4f21-8e8b-4bc301afcdf2", "isDeleted": false, "user": { "timestamp": "2023-03-04", "name": "test", "surname": "password", "email": "test.password@gmail.com" }, "postings": [ { "id": "eeb79bd8-ba20-41b5-a3fd-6377f86236fd", "isDeleted": false, "images": [ { "id": "ea2209e5-63d7-47ab-8d02-60ffb67d86ca", "timestamp": "2023-03-18T13:59:15.630123", "isDeleted": false }, { "id": "8248b0ab-968b-4109-8ebd-f7c6968051e0", "timestamp": "2023-03-18T13:59:17.414993", "isDeleted": false } ] }, { "id": "96c04919-b5c3-4442-a593-a05e661a5ebd", "isDeleted": false } ] }
需求目的
- 将指定post ID对应的
postings.isDeleted设为true - 仅当该post存在
images数组时,将数组内所有图片的isDeleted设为true
当前实现方式
update_result = await dbConnection.find_one_and_update( {"postings.id": id}, [{ "$set": { "postings.$[p].isDeleted": True, "postings.$[p].images.$[].isDeleted" : True # 需要添加判断条件:仅当post存在images字段时才执行该更新 } }], upsert=True, array_filters=[ { "p.id": id, "p.isDeleted": False }] )
当前问题
对存在images数组的文档更新正常,但更新无images字段的post时会报错:
示例1(正常场景)
当post ID为eeb79bd8-ba20-41b5-a3fd-6377f86236fd时,更新结果符合预期:
{ "id": "eeb79bd8-ba20-41b5-a3fd-6377f86236fd", // <- 目标post ID "isDeleted": true, // <- 已更新 "images": [ { "id": "ea2209e5-63d7-47ab-8d02-60ffb67d86ca", "timestamp": "2023-03-18T13:59:15.630123", "isDeleted": true // <- 已更新 }, { "id": "8248b0ab-968b-4109-8ebd-f7c6968051e0", "timestamp": "2023-03-18T13:59:17.414993", "isDeleted": true // <- 已更新 } ] }
示例2(报错场景)
当post ID为96c04919-b5c3-4442-a593-a05e661a5ebd时,触发错误:
pymongo.errors.OperationFailure: Plan executor error during findAndModify :: caused by :: The path 'postings.2.images' must exist in the document in order to apply array updates., full error: {'ok': 0.0, 'errmsg': "Plan executor error during findAndModify :: caused by :: The path 'postings.2.images' must exist in the document in order to apply array updates."
期望效果
- 保持指定post的
isDeleted设为True的功能正常 - 仅当指定post存在
images数组时,才将其中所有图片的isDeleted设为True
解决方案
问题根源是直接指定postings.$[p].images.$[].isDeleted路径时,若该post无images字段,MongoDB会因路径不存在报错。改用聚合管道中的$mergeObjects结合$cond、$map实现条件更新,即可兼容两种场景:
update_result = await dbConnection.find_one_and_update( {"postings.id": id}, [{ "$set": { "postings.$[p]": { "$mergeObjects": [ "$$CURRENT", { "isDeleted": True, "images": { "$cond": { "if": {"$isArray": "$$CURRENT.images"}, "then": { "$map": { "input": "$$CURRENT.images", "as": "img", "in": {"$mergeObjects": ["$$img", {"isDeleted": True}]} } }, "else": "$$CURRENT.images" } } } ] } } }], upsert=True, array_filters=[ { "p.id": id, "p.isDeleted": False } ] )
逻辑说明
- 使用
$mergeObjects合并原post对象与更新内容,避免直接修改不存在的路径 - 通过
$isArray判断当前post是否存在images数组:- 若存在,用
$map遍历数组,为每个图片对象添加/更新isDeleted: True - 若不存在,直接返回原字段(即不新增
images字段)
- 若存在,用
- 无论是否存在
images,都会确保postings.$[p].isDeleted被设置为True
内容的提问来源于stack exchange,提问作者Ahmet-Salman
相关产品推荐
相关产品推荐

