Агрегация MongoDB. $ group, но также собирать данные по несгруппированным полям - PullRequest
1 голос
/ 22 марта 2020

У меня есть функция, с помощью которой пользователи могут оставлять комментарии, а другие пользователи могут отправлять смайлики на комментарии.

Пример данных для 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 входит в систему, поэтому я выбираю комментарии для текущего представления и эмоции каждого комментария.

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, и теперь мой пользовательский интерфейс может отображать это , Я понятия не имею, как это сделать с агрегацией mon go. Я бы тоже не знал, как это сделать с SQL, потому что после группировки данных вы теряете доступ к несгруппированным полям.

1 Ответ

1 голос
/ 22 марта 2020

Вы можете попробовать этот запрос:

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

...