MongoDB查询:拆分key首段生成region集合并添加引用ID
处理MongoDB区域数据拆分与关联需求
需求说明
现有MongoDB集合中存在_id为"officeLocation"的文档,其data数组内的对象key字段为多段格式(例如"APAC - ANZ")。需要完成两项操作:
- 利用正则表达式拆分
key的首段内容,生成唯一区域数据存入名为region的新集合 - 为原
officeLocation文档的data数组中每个对象添加对应区域的referenceId引用
原数据示例
{ "_id": "officeLocation", "data": [ { "_id": ObjectId("60d21b4667d0d8992e610c85"), "key": "APAC - ANZ", "value": "APAC - ANZ" }, { "_id": ObjectId("60d21b4667d0d8992e610c86"), "key": "APAC - Japan", "value": "APAC - Japan" }, { "_id": ObjectId("60d21b4667d0d8992e610c87"), "key": "EMEA - CE - Benelux - Brussels", "value": "EMEA - CE - Benelux - Brussels" }, { "_id": ObjectId("60d21b4667d0d8992e610c88"), "key": "EMEA - CE - Benelux - London", "value": "EMEA - CE - Benelux - London" } ] }
预期结果
region集合数据
{ "_id": ObjectId("60d21b4667d0d8992e610c89"), "key": "APAC", "value": "APAC" }, { "_id": ObjectId("60d21b4667d0d8992e610c8a"), "key": "EMEA", "value": "EMEA" }
更新后的原集合数据
{ "_id": "officeLocation", "data": [ { "_id": ObjectId("60d21b4667d0d8992e610c85"), "key": "APAC - ANZ", "value": "APAC - ANZ", "referenceId": ObjectId("60d21b4667d0d8992e610c89") }, { "_id": ObjectId("60d21b4667d0d8992e610c86"), "key": "APAC - Japan", "value": "APAC - Japan", "referenceId": ObjectId("60d21b4667d0d8992e610c89") }, { "_id": ObjectId("60d21b4667d0d8992e610c87"), "key": "EMEA - CE - Benelux - Brussels", "value": "EMEA - CE - Benelux - Brussels", "referenceId": ObjectId("60d21b4667d0d8992e610c8a") }, { "_id": ObjectId("60d21b4667d0d8992e610c88"), "key": "EMEA - CE - Benelux - London", "value": "EMEA - CE - Benelux - London", "referenceId": ObjectId("60d21b4667d0d8992e610c8a") } ] }
解决方案
步骤1:提取唯一区域并创建region集合
使用聚合管道拆分data数组,提取key的首段区域,去重后写入region集合:
db.your_collection_name.aggregate([ // 筛选目标文档 { $match: { _id: "officeLocation" } }, // 拆分data数组为单个文档 { $unwind: "$data" }, // 提取key的首段区域(匹配第一个" - "之前的内容) { $project: { region: { $regexExtract: { input: "$data.key", regex: "^([^-]+)", captureGroup: 1 } } } }, // 去除首尾空格 { $project: { region: { $trim: { input: "$region" } } } }, // 按区域分组去重 { $group: { _id: "$region" } }, // 构造region集合的文档结构 { $project: { _id: 0, key: "$_id", value: "$_id" } }, // 将结果写入region集合(若集合已存在会覆盖,可用$merge替代) { $out: "region" } ])
若需保留
region集合原有数据,将最后一步的$out替换为$merge: { into: "region", on: "key", whenMatched: "keepExisting" }
步骤2:更新原文档,添加referenceId关联
使用聚合更新操作,关联region集合获取区域ID,更新原文档的data数组:
db.your_collection_name.updateOne( { _id: "officeLocation" }, [ // 关联region集合,获取区域与_id的映射 { $lookup: { from: "region", let: { data: "$data" }, pipeline: [ { $project: { key: 1, regionId: "$_id" } } ], as: "regionMap" } }, // 将regionMap转换为对象,方便后续匹配 { $addFields: { regionMap: { $arrayToObject: { $map: { input: "$regionMap", as: "item", in: { k: "$$item.key", v: "$$item.regionId" } } } } } }, // 更新data数组,添加referenceId { $addFields: { data: { $map: { input: "$data", as: "item", in: { $mergeObjects: [ "$$item", { referenceId: { $getField: { field: { $trim: { input: { $regexExtract: { input: "$$item.key", regex: "^([^-]+)", captureGroup: 1 } } } }, input: "$regionMap" } } } ] } } } } }, // 移除临时的regionMap字段 { $unset: "regionMap" } ] )
注意事项
- 替换命令中的
your_collection_name为实际的集合名称 - 确保MongoDB版本支持
$regexExtract(MongoDB 4.4+),若版本较低可使用$split替代:$arrayElemAt: [{$split: ["$data.key", " - "]}, 0] - 执行
$out前确认region集合无重要数据,或使用$merge避免覆盖
内容的提问来源于stack exchange,提问作者user3741852
相关产品推荐
相关产品推荐

