MongoDB能否基于字段名投影?需提取含name关键字的字段
动态投影MongoDB中字段名包含指定字符串的字段
嘿,这个场景确实挺头疼——手动枚举所有带name的字段不仅繁琐,还容易漏掉变体。MongoDB的常规静态投影(比如$project里列字段)确实不支持直接按字段名的匹配规则来筛选,但我们可以借助聚合管道里的对象转数组+过滤+数组转对象的组合操作,实现完全动态的匹配,不管字段叫name、name-zh还是name-en都能自动捕获。
核心思路
把嵌套的tag对象转换成键值对数组,过滤出键名包含name的元素,再把数组转回对象,最后整理成你想要的输出格式。
具体聚合代码
db.node.aggregate([ // 可选:先筛选出存在符合条件字段的文档,减少后续处理量 { $match: { $expr: { $gt: [ { $size: { $filter: { input: { $objectToArray: "$tag" }, cond: { $ne: [ { $indexOfBytes: ["$$this.k", "name"] }, -1 ] } } } }, 0 ] } } }, // 提取所有含name的tag字段 { $project: { _id: 0, filteredTags: { $arrayToObject: { $filter: { input: { $objectToArray: "$tag" }, cond: { $ne: [ { $indexOfBytes: ["$$this.k", "name"] }, -1 ] } } } } } }, // 把过滤后的字段提升为顶层文档(和你期望的输出格式一致) { $replaceRoot: { newRoot: "$filteredTags" } } ])
代码解释
$match阶段:先过滤掉完全没有含name字段的文档,避免无效计算。这里用$objectToArray把tag转成数组,再用$filter统计符合条件的元素数量,只要数量大于0就保留该文档。$project阶段:- 用
$objectToArray: "$tag"把tag对象转成[{k: "字段名", v: "字段值"}, ...]的数组格式 - 用
$filter筛选出k(字段名)中包含name的元素($indexOfBytes返回匹配的起始位置,不等于-1表示存在) - 再用
$arrayToObject把过滤后的数组转回对象
- 用
$replaceRoot阶段:把嵌套在filteredTags里的结果提升为顶层文档,就得到了你想要的输出格式。
扩展:不区分大小写匹配
如果需要匹配不区分大小写的name(比如Name、NAME-zh),可以把$indexOfBytes改成结合$toLower的$indexOfCP:
cond: { $ne: [ { $indexOfCP: [ { $toLower: "$$this.k" }, "name" ] }, -1 ] }
输出结果
运行上述代码后,你的示例文档会输出:
{ "name" : "HongKong", "name-zh" : "香港" } { "name-en" : "Beijing" }
完全符合你的期望。
内容的提问来源于stack exchange,提问作者陈梓泉
相关产品推荐
相关产品推荐

