как использовать $ elemMatch для массива, указав верхнее поле как часть запроса - PullRequest
0 голосов
/ 11 февраля 2020

Я бы хотел получить для определенного пользователя c его чаты с непрочитанными сообщениями.

Допустим, у меня есть упрощенная модель чата, подобная этой:

{
  lastMessageAt: Date,
  participants: [
    {
      user: String(id),
      lastReadAt: Date
    }
  ]
}

Как я могу выполнить свой запрос?

Я пробовал несколько вещей, например, с $ elemMatch, но lastMessageAt неизвестно на этом уровне ...

ChatDB.find({
  'participants': {
    $elemMatch: { user: '12345', lastReadAt: { $lt: '$lastMessageAt' } }
  }
}

Заранее спасибо за вашу помощь! :)

Ответы [ 2 ]

0 голосов
/ 11 февраля 2020

Я нашел решение, которое заключается в использовании агрегатора с оператором $ unwind.

await ChatDB.aggregate([
      {
        $unwind: '$participants'
      },
      {
        $match: {
          'participants.user': '12345',
          $expr: {
            $lt: [
              '$participants.lastReadAt',
              '$lastMessageAt'
            ]
          }
        }
      }]);

Надеюсь, это будет полезно

0 голосов
/ 11 февраля 2020
Оператор

$elemMatch найдет в коллекции ChatDB те документы, в которых содержит хотя бы 1 элемент в participants, соответствующий вашим критериям. Также мое исследование закончилось выводом о том, что пока нет возможности получить доступ к другому полю документа в операторе $elemMatch. В любом случае, если это ваша цель, то вы можете использовать этот запрос:

ChatDB.aggregate([
  {
    $match: {
      "participants.user": "12345",
      $expr: {
        $lt: [
          "$participants.lastReadAt",
          "$lastMessageAt"
        ]
      }
    }
  }
])

Пн go детская площадка

Если вы также хотите фильтровать participants что действительно соответствует критериям, то вам нужно добавить проекция этап:

ChatDB.aggregate([
  {
    $match: {
      "participants.user": "12345",
      $expr: {
        $lt: [
          "$participants.lastReadAt",
          "$lastMessageAt"
        ]
      }
    }
  },
  {
    $project: {
      participants: {
        $filter: {
          input: "$participants",
          as: "participant",
          cond: {
            $and: [
              {
                $eq: [
                  "$$participant.user",
                  "12345"
                ]
              },
              {
                $lt: [
                  "$$participant.lastReadAt",
                  "$lastMessageAt"
                ]
              }
            ]
          }
        }
      }
    }
  }
])

Пн go детская площадка

...