MongoDB聚合中如何将date数组字段拆分为相邻两个独立字段
MongoDB聚合将date数组元素映射为独立命名字段实现方案
根据数组长度是否固定,可选择两种实现方式:
场景1:date数组长度固定
如果所有文档的date数组长度为已知固定值(比如示例中固定为2),直接在$project/$set阶段通过$arrayElemAt按索引取值即可,写法最简单、执行性能最优:
db.yourCollection.aggregate([ { $project: { // _id默认会保留,无需额外声明 date1: { $arrayElemAt: ["$date", 0] }, // 数组第1个元素对应date1,索引从0开始 date2: { $arrayElemAt: ["$date", 1] } // 数组第2个元素对应date2 // 数组长度更长时,按顺序追加dateN,对应数组索引为n-1即可 } } ])
该方式执行后输出结构和需求给出的示例完全一致。
场景2:date数组长度不固定
如果不同文档的date数组长度不一致,需要动态按数组实际长度生成date1/date2/.../dateN字段,可通过$arrayToObject结合$map动态构造字段,无需提前约定数组长度:
db.yourCollection.aggregate([ { $replaceRoot: { newRoot: { $mergeObjects: [ // 保留原文档除date数组外的所有字段(包含_id) { $arrayToObject: { $filter: { input: { $objectToArray: "$$ROOT" }, cond: { $ne: ["$$this.k", "date"] } } } }, // 按数组顺序动态生成带序号的date字段 { $arrayToObject: { $map: { input: { $range: [0, { $size: "$date" }] }, in: { k: { $concat: ["date", { $toString: { $add: ["$$this", 1] } }] }, v: { $arrayElemAt: ["$date", "$$this"] } } } } } ] } } } ])
核心逻辑说明
- 用
$range生成从0到数组长度的连续索引序列 - 用
$map遍历索引,将每个索引对应的日期组装为{k: 字段名, v: 日期值}的键值结构,字段名序号为索引值+1 - 用
$arrayToObject将键值结构转换为正式的文档字段 - 用
$mergeObjects合并原文档保留字段和新生成的date字段,最后通过$replaceRoot输出为最终文档结构
内容的提问来源于stack exchange,提问作者Charles Fonseca
相关产品推荐
相关产品推荐

