如何通过MongoDB聚合提取含嵌套字段的点分隔全量键名列表
解决方案
你可以直接使用MongoDB 4.4+版本支持的$function聚合运算符实现需求,该语法在Atlas免费版完全可用,不需要调用map-reduce能力,你已经写好的JS递归逻辑稍作优化即可直接嵌入聚合管道运行:
完整可运行聚合代码
db.customers.aggregate([ // 单文档维度提取所有嵌套键 { $project: { keys: { $function: { body: function(obj) { const keys = []; const idRegex = new RegExp('_id.*'); // 递归提取深度嵌套键 function getDeepKeys(currentObj, parentKey = '') { for (const key in currentObj) { // 过滤所有_id相关字段 if (idRegex.test(key)) continue; // 拼接带点运算符的全字段名 const fullKey = parentKey ? `${parentKey}.${key}` : key; keys.push(fullKey); // 仅处理非null、非数组类型的嵌套对象,避免生成冗余错误键 if (typeof currentObj[key] === 'object' && currentObj[key] !== null && !Array.isArray(currentObj[key])) { getDeepKeys(currentObj[key], fullKey); } } } getDeepKeys(obj); return keys; }, args: ["$$ROOT"], lang: "js" } } } }, // 汇总所有文档的键 { $group: { _id: null, allKeys: { $addToSet: "$keys" } } }, // 扁平化数组+去重得到最终结果 { $project: { _id: 0, finalKeys: { $reduce: { input: "$allKeys", initialValue: [], in: { $setUnion: ["$$value", "$$this"] } } } } } ]).toArray()[0].finalKeys
测试输出
针对你给出的示例文档,运行后输出和预期完全一致:
[ 'name', 'address', 'documentType', 'personalDetails', 'personalDetails.gender', 'personalDetails.age', 'personalDetails.position' ]
如果需要处理数组类型字段内部的嵌套文档键,只需要在递归逻辑中增加数组判断、遍历数组元素提取键即可。
内容的提问来源于stack exchange,提问作者Wilbur Dsouza
相关产品推荐
相关产品推荐

