MongoDB arrayFilters更新时$concat被当作普通值而非操作符问题
问题原因
你遇到这个问题的核心原因是普通更新语法下的$set操作符不支持直接执行聚合表达式:
- 你当前使用的是MongoDB传统更新写法,更新参数是普通对象而非数组,这种场景下
$set只会把右侧的值当做常量直接写入文档,不会解析$concat这类聚合操作符,所以最终把整个$concat配置对象存进了字段里。 - 聚合操作符(比如
$concat、$sum等)只能在聚合管道、或者聚合管道形式的更新语句中被识别执行,传统更新语法不支持这类基于原有字段值的动态计算逻辑。 - 另外你写的
$Log.$[i].ScriptLogs.$[j].StdOut这种带数组过滤占位符的字段引用,也只能在传统更新的数组过滤逻辑里用来定位元素,不能在聚合表达式中用来取值。
正确实现方式
MongoDB 4.2及以上版本支持聚合管道形式的更新(把更新参数放在数组中即可触发),你可以通过$map遍历嵌套数组,匹配到目标元素后做字符串拼接,语句如下:
db.getCollection("ServerEntitys").update( {_id: '556ebf103a8b4c3d067bb6466df7c0651c53a1ff79fa348edff656586c24ad0c'}, [ { $set: { Log: { $map: { input: "$Log", as: "logItem", in: { $mergeObjects: [ "$$logItem", { ScriptLogs: { $map: { input: "$$logItem.ScriptLogs", as: "scriptLog", in: { $cond: { if: { $and: [ {$eq: ["$$logItem.ScriptName", "UpdateScript"]}, {$eq: ["$$scriptLog.ID", "f5bd1fefb2a5c4712ea1d35eb5bd309074984c5932db3723cc29f8d92258a3fa"]} ] }, then: {$mergeObjects: ["$$scriptLog", {StdOut: {$concat: ["$$scriptLog.StdOut", "World"]}}]}, else: "$$scriptLog" } } } } } ] } } } } } ] )
执行上述语句后,目标StdOut字段就会被更新为你预期的HelloWorld。
注意:如果你的MongoDB版本低于4.2,不支持聚合管道更新,就需要先把文档查询到业务层拼接完成后,再执行更新操作写回数据库。
内容的提问来源于stack exchange,提问作者MeD
相关产品推荐
相关产品推荐

