MongoDB 聚合:计算对象数组中的出现次数并转换为对象

MongoDB Aggregate: count occurrences in array of object and transform to object

我有一个名为 notifications 的集合,它有 2 个字段(为简单起见):

示例:

{
   targets: ['group1', 'group2'],
   userReads: [
     {userId: 1, readAt: 'date1'},
     {userId: 2, readAt: 'date2'},
     {userId: 3, readAt: 'date3'},
   ]
}

{
   targets: ['group1'],
   userReads: [
     {userId: 1, readAt: 'date4'}
   ]
}

期望的输出:

{
   groupsNotificationsCount: {
     group1: 2,
     group2: 1
   },
   usersNotificationsCount: {
     1: 2,
     2: 1,
     3: 1
   }
}

起初我尝试了这个聚合:

[{
 $match: {
  targets: {
   $in: ['group/1','group/2']
  },
 }
}, {
 $project: {
  targets: 1,
  userReads: 1
 }
}, {
 $unwind: {
  path: '$targets'
 }
}, {
 $match: {
  targets: {
   $in: ['group/1','group/2']
  }
 }
}, {
 $group: {
  _id: '$targets',
  countForGroup: {
   $count: {}
  },
  userReads: {
   $push: '$userReads'
  }
 }
}, {
 $addFields: {
  userReads: {
   $reduce: {
    input: '$userReads',
    initialValue: [],
    'in': {
     $concatArrays: [
      '$$value',
      '$$this'
     ]
    }
   }
  }
 }
}]

我的文档中每个组的计数都是正确的,如下所示:

{
   _id: 'group1',
   countForGroup: 2,
   userReads: [
     {userId: 1, readAt: 'date1'},
     {userId: 2, readAt: 'date2'},
     {userId: 3, readAt: 'date3'},
     {userId: 1, readAt: 'date4'},
   ]
}

但现在我不知道如何从那里继续获得我想要的输出

这是使用 $facet 的完美用例。您可以通过 $unwind$group 计数分别处理 groupsNotificationsCountusersNotificationsCount。之后通过争论成 k-v 元组数组,您可以使用 $arrayToObject

构造您期望的形式
db.collection.aggregate([
  {
    "$facet": {
      "groupsNotificationsCount": [
        {
          "$unwind": "$targets"
        },
        {
          $group: {
            _id: "$targets",
            count: {
              $sum: 1
            }
          }
        }
      ],
      "usersNotificationsCount": [
        {
          "$unwind": "$userReads"
        },
        {
          $group: {
            _id: "$userReads.userId",
            count: {
              $sum: 1
            }
          }
        }
      ]
    }
  },
  {
    "$project": {
      groupsNotificationsCount: {
        "$arrayToObject": {
          "$map": {
            "input": "$groupsNotificationsCount",
            "as": "g",
            "in": {
              k: "$$g._id",
              v: "$$g.count"
            }
          }
        }
      },
      usersNotificationsCount: {
        "$arrayToObject": {
          "$map": {
            "input": "$usersNotificationsCount",
            "as": "u",
            "in": {
              k: {
                $toString: "$$u._id"
              },
              v: "$$u.count"
            }
          }
        }
      }
    }
  }
])

这里是Mongo playground供大家参考。