You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB聚合$sum带条件:缺失属性时取消求和的实现方法

解决方案:按组全字段存在性判断后求和

当然可行!你的需求核心是仅当组内所有文档都包含目标字段时才求和,否则返回null,而MongoDB默认的$sum操作会把缺失字段当作0处理,这就是为什么你的初始查询无法满足要求。我们需要通过额外的阶段来判断组内字段的存在性,再决定是否返回求和结果。

实现思路

  1. 标记字段存在性:先给每个文档添加标记,说明它是否包含length和area字段;
  2. 分组统计与校验:按name分组时,同时统计组内是否所有文档都包含目标字段(用$min判断,因为布尔值true对应1,false对应0,$min为1则表示全组都有该字段);
  3. 条件返回结果:根据校验结果,返回求和值或null。

完整Mongoose聚合代码

let query = mongoose.model('mycollection').aggregate([
  // 阶段1:标记每个文档是否包含length/area字段
  {
    $project: {
      name: 1,
      length: 1,
      area: 1,
      hasLength: { $exists: ["$length", true] },
      hasArea: { $exists: ["$area", true] }
    }
  },
  // 阶段2:分组统计,同时校验全组字段存在性
  {
    $group: {
      _id: { name: "$name" },
      count: { $sum: 1 },
      allHaveLength: { $min: "$hasLength" }, // 1=全组都有length,0=至少一个缺失
      allHaveArea: { $min: "$hasArea" },     // 1=全组都有area,0=至少一个缺失
      totalLength: { $sum: "$length" },
      totalArea: { $sum: "$area" }
    }
  },
  // 阶段3:根据校验结果返回求和值或null
  {
    $project: {
      count: 1,
      summarizedLength: {
        $cond: ["$allHaveLength", "$totalLength", null]
      },
      summarizedArea: {
        $cond: ["$allHaveArea", "$totalArea", null]
      }
    }
  }
]);

结果验证

针对你提供的测试数据:

[ 
  { name: 'abc', length: 25, area: 10 }, 
  { name: 'abc', length: 5 } 
]

执行上述查询后,会得到你期望的输出:

[ 
  { count: 2, summarizedLength: 30, summarizedArea: null, _id: { name: 'abc' } } 
]

补充说明

  • 如果希望缺失时不显示该字段而非返回null,可以将$cond的else分支改为$$REMOVE(MongoDB 3.6+支持),比如:
    summarizedArea: {
      $cond: ["$allHaveArea", "$totalArea", "$$REMOVE"]
    }
    
  • 用$min判断全组字段存在性比$allElementsTrue更高效,因为不需要存储整个组的标记数组,直接通过最小值判断即可。

内容的提问来源于stack exchange,提问作者Joe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:08:07