MongoDB嵌套数组更新报错:如何向rule1子数组推送新元素?
问题分析与修复方案
错误原因
你使用了MongoDB的位置操作符$,但查询条件里没指定匹配rules数组中包含rule1的元素,导致MongoDB无法定位到要更新的数组项,因此抛出The positional operator did not find the match needed from the query错误。
位置操作符$的作用是匹配查询条件中第一个符合要求的数组元素位置,而你的查询只指定了_id,没有对rules数组内的元素做筛选,所以$找不到对应的位置。
修复方法
方法1:使用过滤位置操作符 $[<identifier>](推荐)
这种方式能精准定位rules数组中包含rule1的对象,不依赖查询匹配顺序,更可靠:
all_updates = { "$push": {"rules.$[elem].rule1": {"hash": "cccc", "date": "34"}} } collection.update_one( {"_id": _id}, all_updates, array_filters=[{"elem.rule1": {"$exists": True}}] )
array_filters=[{"elem.rule1": {"$exists": True}}]:指定只对rules数组中存在rule1字段的元素(也就是第一个数组项)执行更新。rules.$[elem].rule1:通过elem标识符定位到符合过滤条件的元素,再向它的rule1子数组推送新元素。
方法2:在查询条件中匹配rule1,再用位置操作符$
如果你的rules数组里只有一个带rule1的元素,可以在查询条件里加上对rules.rule1的匹配,让$定位到该元素:
all_updates = { "$push": {"rules.$.rule1": {"hash": "cccc", "date": "34"}} } collection.update_one( {"_id": _id, "rules.rule1": {"$exists": True}}, all_updates )
这里查询条件"rules.rule1": {"$exists": True}会匹配到包含rule1的rules数组项,位置操作符$就会指向这个项,完成推送操作。
额外优化建议
你当前的文档结构里,rules是数组,每个元素是单独的rule1/rule2对象,其实可以优化成更简洁的结构:
rules: { rule1: [{"hash":"aaa", "date": "1/1/1"}, ...], rule2: [{"hash":"ddd", "date": "4/4/4"}, ...], rule3: [{"hash":"fff", "date": "6/6/6"}, ...] }
把rules设为对象而非数组后,更新rule1时无需处理数组定位,直接写$push: {"rules.rule1": ...}即可,操作更简单。
内容的提问来源于stack exchange,提问作者wondergrandma
相关产品推荐
相关产品推荐

