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

如何在MongoDB的$group中带条件使用$addToSet?

解决MongoDB分组时条件生成数组元素的问题

原始文档

_id: ObjectId('641316fd596514e63a2121ca'),
orgId: 3,
devices {
    _id: ObjectId('64131139596514e63a2121c1')
    name: 'Device A'
}

```javascript _id: ObjectId('641316fd596514e63a2121ca'), orgId: 3 ```
```javascript _id: ObjectId('64131b2b596514e63a2121ce'), orgId: 4, devices { _id: ObjectId('64131c1e596514e63a2121d0') name: 'Device B' } ```
```javascript _id: ObjectId('64131d38596514e63a2121d1'), orgId: 5 ```
```javascript _id: ObjectId('64131d38596514e63a2121d1'), orgId: 5 ```

需求

按_id和orgId对文档分组,生成名为endpoints的数组:

  • 仅当文档存在devices字段时,向数组添加元素:{ type: 'linux', refId: '$devices._id' }
  • 无devices字段的文档分组后,endpoints为空数组

预期结果:

_id: {
    id: ObjectId('641316fd596514e63a2121ca'),
    orgId: 3
},
endpoints: [
    { type: 'linux', refId: ObjectId('64131139596514e63a2121c1') }
]

```javascript _id: { id: ObjectId('64131b2b596514e63a2121ce'), orgId: 4 }, endpoints: [ { type: 'linux', refId: ObjectId('64131c1e596514e63a2121d0') } ] ```
```javascript _id: { id: ObjectId('64131d38596514e63a2121d1'), orgId: 5 }, endpoints: [] ```

尝试的代码

{
  $group: {
    _id: {
      id: '$_id',
      orgId: '$orgId',
    },
    endpoints: { 
      $addToSet: {
        $cond: {
          if: { 
            $ne: [ '$devices', undefined ] 
          },
          then: { 
            type: 'linux',
            refId: '$devices._id'
          },
          else: '$$REMOVE'
        }
      }
    }
  }
}

问题

执行后,无devices字段的分组中,endpoints数组出现了仅含type: 'linux'的对象,而非预期的空数组:

_id: {
    id: ObjectId('64131d38596514e63a2121d1'),
    orgId: 5
},
endpoints: [
    { type: 'linux' }
]

解决方案

修正后的聚合管道

[
  {
    $group: {
      _id: {
        id: '$_id',
        orgId: '$orgId'
      },
      endpoints: {
        $push: {
          $cond: {
            // 准确判断devices字段是否存在
            if: { $exists: ['$devices', true] },
            then: {
              type: 'linux',
              refId: '$devices._id'
            },
            else: '$$REMOVE'
          }
        }
      }
    }
  },
  {
    $addFields: {
      // 过滤数组中的空元素,确保无符合条件的元素时数组为空
      endpoints: {
        $filter: {
          input: '$endpoints',
          cond: { $ne: ['$$this', null] }
        }
      }
    }
  }
]

关键修正点

  1. 字段存在性判断:用$exists: ['$devices', true]替代$ne: ['$devices', undefined],MongoDB中字段缺失时不会被识别为undefined,$exists能准确判断字段是否存在。
  2. 数组元素过滤:添加$addFields阶段配合$filter,移除endpoints数组中因$$REMOVE产生的空元素,确保无符合条件的文档时数组为空。
  3. 数组操作选择:用$push替代$addToSet(若需去重可保留$addToSet),更直接地收集符合条件的元素。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 17:42:31