MongoDB聚合管道:为数组字段内文档新增计算权重字段
MongoDB 聚合为数组内嵌文档增补计算字段实现方案
最优实现(适配MongoDB 3.6+)
db.pos.aggregate([ { $addFields: { holdings: { $map: { input: "$holdings", as: "hold_item", in: { $mergeObjects: [ "$$hold_item", { wt: { $divide: ["$$hold_item.shares", { $sum: "$holdings.shares" }] } } ] } } } } } ])
逻辑说明
- 使用
$addFields默认保留主文档所有原有字段,无需手动枚举待保留字段,避免结构遗漏 $map遍历holdings数组的每个子文档,通过$mergeObjects将原有子文档的全量字段与新增的wt字段合并,实现原位增补效果- 由于
$map的遍历别名hold_item不会覆盖根字段作用域,可直接在分母位置通过$sum聚合当前主文档原始holdings数组的全部shares值,无需额外生成临时总股份字段 - 如果当前数据集数据量较大,建议改用低版本兼容的临时字段方案,可避免总股份数被重复计算,提升性能
低版本兼容实现(适配MongoDB <3.6,无$mergeObjects)
db.pos.aggregate([ // 临时计算当前主文档的总持仓股份数 { $addFields: { total_shares: { $sum: "$holdings.shares" } } }, // 遍历holdings数组,手动合并原有字段与新增wt { $addFields: { holdings: { $map: { input: "$holdings", as: "hold_item", in: { fid: "$$hold_item.fid", shares: "$$hold_item.shares", // 若子文档后续新增其他字段,需在此处手动追加 wt: { $divide: ["$$hold_item.shares", "$total_shares"] } } } } } }, // 删除临时生成的total_shares字段,恢复原文档结构 { $unset: "total_shares" } ])
常见踩坑点
- 若使用
$project阶段处理,必须显式声明待保留的主文档字段(如asof:1、portfolio_id:1等),否则未声明的字段会被直接过滤,优先用$addFields/$set做字段增补 - 总股份计算时需注意作用域,若错误将
$$hold_item.shares作为$sum的输入,会导致总和计算为单个子文档的股份值,最终所有wt结果均为1 - 不要手动枚举子文档字段,否则后续子文档新增字段会被直接过滤,无法满足原位增补的结构保留要求
内容的提问来源于stack exchange,提问作者user3173412
相关产品推荐
相关产品推荐

