【问题标题】:MongoDB aggregation. $group but also collect data on non-grouped fieldsMongoDB 聚合。 $group 还收集非分组字段的数据
【发布时间】:2020-03-22 14:11:51
【问题描述】:

我有一个功能,用户可以发布 cmets,其他用户可以发布对 cme​​ts 的 emoji 反应。

db.emotes 的示例数据:

{ "_id" : 'a', "commentId" : 'commentA', "userId" : "userA", "emote" : "emoteA" }
{ "_id" : 'b', "commentId" : 'commentA', "userId" : "userB", "emote" : "emoteA" }
{ "_id" : 'c', "commentId" : 'commentA', "userId" : "userC", "emote" : "emoteB" }

对于commentA,2 位用户回复了emoteA,1 位用户回复了emoteB

假设userA 登录,所以我获取当前视图的cmets,以及每个评论的表情。

async listEmotesForCommentId (commentId) {
    const emotes = db.get().collection('emotes')
    return emotes.aggregate([
        { $match: { commentId: new ObjectID(commentId) } },
        {
            $group: {
                _id: '$emote',
                count: { $sum: 1 }
            }
        },
        {
            $project: {
                _id: 0,
                emote: '$_id',
                count: 1,
            }
        }
    ]).toArray()
}

//
const emotes = await listEmotesForCommentId('commentA')
/*
[
  { count: 2, emote: 'emoteA' },
  { count: 1, emote: 'emoteB' },
]
*/

现在,问题来了。如果请求用户对该评论做出反应,我想要一个字段hasReacted: <boolean>。所以现在函数签名是listEmotesForCommentId (commentId, userId),我想要的结果是

const emotes = await listEmotesForCommentId('commentA', 'userA')
/*
[
  { count: 2, emote: 'emoteA', hasReacted: true },
  { count: 1, emote: 'emoteB', hasReacted: false },
]
*/

这个结果意味着userA 是对emoteA 做出反应的用户之一,现在我的 UI 可以显示它。我不知道如何使用 mongo 聚合来做到这一点。我也不知道如何用 SQL 来做,因为一旦你对数据进行分组,你就失去了对非分组字段的访问权限。

【问题讨论】:

    标签: node.js mongodb mongodb-query aggregation-framework


    【解决方案1】:

    你可以试试这个查询:

    emotes.aggregate([
      { $match: { commentId: new ObjectID(commentId) } },
      {
        $group: {
          _id: "$emote",
          count: { $sum: 1 },
          users: {
             $push: "$userId" // Push all users to users field
          }
        }
      },
      {
        $project: {
          _id: 0,
          emote: "$_id",
          count: 1,
          /** Conditional check if pass'd in value 'userA' exists in 'users' array before assigning a value to hasReacted field */
          hasReacted: { $cond: [{ $in: ["userA", "$users"] }, true, false] }
        }
      }
    ]);
    

    测试: MongoDB-Playground

    【讨论】:

    • 是的,谢谢。作品。所以这里的关键思想是我可以在 $group 阶段收集额外的非分组数据,并在以后的聚合操作中使用它?
    • 顺便说一句,您的答案与您的链接不同。 users 应该在 $group 对象内,这对我有用。
    • @EricGuan : 哦,抱歉,在向现有代码添加逻辑时打错了 :-) 是的,当涉及到 non-grouped data 时,您可以在组中执行多项操作,您可以使用 $addFields 而不是 @ 987654327@ 将唯一值存储在 users 数组中,或者您可以使用 $$ROOT 存储整个当前文档,而不仅仅是 userId 等等..
    猜你喜欢
    • 2016-03-08
    • 2014-02-27
    • 2019-03-27
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多