mongoDB聚合:计数在对象数组中的发生并转换为对象

发布于 2025-02-03 08:46:07 字数 1663 浏览 4 评论 0原文

我有一个称为通知的集合,该集合具有2个字段(为简单起见):

  • targets是字符串数组

  • userreads是对象的数组{userId,readat}

示例:

{
   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'},
   ]
}

但是现在我不知道该如何从那里继续以获取所需的输出

I have a collection called notifications that has 2 fields (for simplicity):

  • targets is an array of strings

  • userReads is an array of object {userId, readAt}

Example :

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

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

DESIRED OUTPUT:

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

At first I tried this aggregate:

[{
 $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'
     ]
    }
   }
  }
 }
}]

I have the right counts for each group in my documents like so:

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

But now I have no idea how to go on from there to get my desired output

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小镇女孩 2025-02-10 08:46:07

这是使用$ facet的完美用例。您可以通过$ Untind$组 $ group 分别处理 groups notificationcount usernotificationcount 。之后,通过使用$ 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 供您参考。

This is a perfect use case for using $facet. You can process groupsNotificationsCount and usersNotificationsCount separately by $unwind and $group the count. Afterwards by wrangling into array of k-v tuples, you can construct your expected form by using $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"
            }
          }
        }
      }
    }
  }
])

Here is the Mongo playground for your reference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文