MongoDB动态键路径匹配查询与批量更新问题
问题描述
现有MongoDB文档结构如下:
{ "_id": "1234", "Nodes": { "-14": { "_t": "DL", "Key": "-14", "Edges": [ { "TargetNode": "-5" } ], "Title": "Lookup", "Text": "Data Lookup", "ConnectionString": "Server=LOCALSERVER;Database=DataCache;User=sa;Password=1234;", "TableName": "Customers", "FieldMaps": [ { "ID": 2, "Column": "Name" }, { "ID": 1, "Column": "Number" } ] } } }
需要执行updateMany操作,将所有文档中Nodes下任意动态负数值键对应的ConnectionString里的Server=LOCALSERVER替换为Server=NEWSERVER。但当前查询环节遇到问题:Nodes下的节点ID(如-14)是随文档变化的动态值,使用固定键名的查询只能匹配特定文档,而MongoDB不支持直接在键名中使用正则匹配。
尝试过的无效查询:
db.getCollection('workflows').find({"Nodes.{$regex: '-\\d{1,}'}.ConnectionString": {$regex: /^Server=LOCALSERVER/}})
解决方案
1. 查询匹配文档
利用$expr结合$objectToArray将Nodes对象转换为键值对数组,再通过$anyElementTrue检查是否存在符合条件的节点:
db.getCollection('workflows').find({ $expr: { $anyElementTrue: { $map: { input: { $objectToArray: "$Nodes" }, as: "node", in: { $and: [ // 匹配键为负数值格式(可选,若只需要负数值键的节点) { $regexMatch: { input: "$$node.k", regex: /^-\d+$/ } }, // 匹配ConnectionString包含目标值 { $regexMatch: { input: "$$node.v.ConnectionString", regex: /^Server=LOCALSERVER/ } } ] } } } } })
如果不需要限制节点键为负数值格式,可去掉$and中的第一个条件。
2. 执行批量更新
使用聚合管道模式的updateMany,通过$objectToArray、$map和$arrayToObject动态遍历并修改所有符合条件的节点:
db.getCollection('workflows').updateMany( // 查询条件同上述查询语句 { $expr: { $anyElementTrue: { $map: { input: { $objectToArray: "$Nodes" }, as: "node", in: { $and: [ { $regexMatch: { input: "$$node.k", regex: /^-\d+$/ } }, { $regexMatch: { input: "$$node.v.ConnectionString", regex: /^Server=LOCALSERVER/ } } ] } } } } }, [ { $set: { Nodes: { $arrayToObject: { $map: { input: { $objectToArray: "$Nodes" }, as: "node", in: { k: "$$node.k", v: { $mergeObjects: [ "$$node.v", { ConnectionString: { $cond: [ { $and: [ { $regexMatch: { input: "$$node.k", regex: /^-\d+$/ } }, { $regexMatch: { input: "$$node.v.ConnectionString", regex: /^Server=LOCALSERVER/ } } ] }, // 替换目标字符串 { $replaceOne: { input: "$$node.v.ConnectionString", find: "Server=LOCALSERVER", replacement: "Server=NEWSERVER" } }, // 不符合条件的保持原字符串 "$$node.v.ConnectionString" ] } } ] } } } } } } } ] )
关键逻辑说明
$objectToArray: 将Nodes对象转换为[{k: "键名", v: "值对象"}]格式的数组,方便遍历处理动态键。$map: 遍历数组中的每个节点,对符合条件的节点执行字符串替换。$arrayToObject: 将处理后的数组转换回对象格式,更新原Nodes字段。$mergeObjects: 保留节点原有其他字段,只修改ConnectionString。
内容的提问来源于stack exchange,提问作者Mate19
相关产品推荐
相关产品推荐

