MongoDB如何将动态字段数组转换为单个扁平对象
MongoDB 动态表单数组转顶层键值对实现方案
以下方案可直接将Fields数组内的动态字段扁平化为文档顶层属性,同时保留原_id字段。
方案一:MongoDB 4.2及以上版本推荐(通用动态字段方案)
该方案无需提前预知FieldId列表,完全适配动态表单的可变字段场景,执行效率最高。
聚合语句如下,使用时将your_collection_name替换为实际集合名即可:
db.your_collection_name.aggregate([ { $replaceRoot: { newRoot: { $mergeObjects: [ { _id: "$_id" }, { $arrayToObject: { $map: { input: "$Fields", in: { k: "$$this.FieldId", v: "$$this.Value" } } } } ] } } } ])
语句逻辑说明
- 用
$map遍历Fields数组,将每个元素转换为{k: 字段唯一标识, v: 字段值数组}的标准键值对结构,适配$arrayToObject的输入要求 - 用
$arrayToObject将键值对数组直接转换为普通对象,所有FieldId会自动成为对象的顶层键,对应Value直接作为键值 - 用
$mergeObjects将原文档的_id字段和转换后的字段对象合并,最后通过$replaceRoot将合并后的对象作为最终输出的根文档
*如果需要过滤掉不需要返回的字段(比如示例目标结果中排除了两个FieldId对应的字段),可以在聚合最前方增加$addFields阶段过滤Fields数组内容:
// 带字段过滤的版本,按需使用 db.your_collection_name.aggregate([ { $addFields: { Fields: { $filter: { input: "$Fields", cond: { $not: { $in: [ "$$this.FieldId", // 数组内填写需要排除的FieldId即可 ["e97d0386-cd42-6277-1207-e674c3268cec", "35e55d27-7d2c-467d-8a88-09ad6c9f5631"] ] } } } } } }, // 接上述$replaceRoot转换阶段 { $replaceRoot: { newRoot: { $mergeObjects: [ { _id: "$_id" }, { $arrayToObject: { $map: { input: "$Fields", in: { k: "$$this.FieldId", v: "$$this.Value" } } } } ] } } } ])
方案二:低版本MongoDB兼容方案(固定字段场景)
如果使用4.2以下版本MongoDB,且所有FieldId固定已知,可以通过$project配合数组索引定位实现,该方案无法适配动态新增的字段,非必要不推荐:
db.your_collection_name.aggregate([ { $project: { _id: 1, "e8efd0b0-9d10-4584-bb11-5b24f189c03b": { $arrayElemAt: [ "$Fields.Value", { $indexOfArray: ["$Fields.FieldId", "e8efd0b0-9d10-4584-bb11-5b24f189c03b"] } ] }, // 其余字段按照上述格式逐个添加映射规则即可 "fa6745c2-b259-4a3b-8c6f-19eb78fbbbf5": { $arrayElemAt: [ "$Fields.Value", { $indexOfArray: ["$Fields.FieldId", "fa6745c2-b259-4a3b-8c6f-19eb78fbbbf5"] } ] } } } ])
内容的提问来源于stack exchange,提问作者Mani J
相关产品推荐
相关产品推荐

