MongoDB - получить документы с размером вложенного массива после фильтрации - PullRequest
0 голосов
/ 25 октября 2018

Проблема:

Я пытаюсь получить список документов и для каждого из них рассчитать количество вхождений данного значения в один и тот же вложенный массивdocument.

У меня есть рабочий пример использования структуры агрегации, но мне интересно, есть ли лучший способ сделать то же самое, поэтому я могу сравнить различные подходы.

Упрощенная модель данных:

Отдельный документ в сборнике "Raffles":

{
  "_id" : objectId,
  "name" : string,
  "ends_at" : ISODate/Timestamp,
   ...
  "subscribers" : string[] //List of user ids
}
  • Коллекциисостоит из документов, представляющих лотерею / лотерею с названием и датами начала / окончания.
  • Пользователи могут подписаться на лотерею.
  • Пользователи могут подписаться несколько раз на одну и ту же лотерею.

95% запросов на чтение потребуют как данные лотереи, такие как имя, описание и даты + информация о подписанных пользователях.Вот почему я решил хранить все в одном лотерейном документе вместо: ссылки на подписанные лотереи в пользовательском документе или отдельную коллекцию с лотереями и количеством подписок.

Альтернатива может быть?:

Массив subscribers представляет собой список строк, представляющих идентификатор пользователя.Таким образом, добавить подписчика так же просто, как нажать новое значение.Другой вариант - создать массив объектов, подобных этому, и увеличить счетчик:

{
  "subscribers: [
     {
       "id": objectId  //User id
       "count": integer //Number of subscriptions
     },
     ...
  ]
}

Ожидаемый результат:

Ожидаемый результат - полная лотереяdocument + дополнительное значение количества подписок данного пользователя.

{
    "_id" : objectId,
    "name" : string,
    "ends_at" : ISODate/Timestamp,
     ...
    "subscriptions" : 3 //Number of entries for a given user
}

Текущее решение

Я получаю размер после фильтрации вложенного массива с помощьюзаданный идентификатор пользователя

db.raffles.aggregate([
    ...
    {
        $project: {
            "name" : 1,
            "ends_at" :1,
             ...
            "subscriptions" : {
                 $size : {
                    $filter : {
                        input: "$subscribers",
                        as: "user",
                        cond: {
                            $eq: ["$$user", <USER_ID>]
                        },
                    }
                 }
            }
        }
    }
    ...
])

Вопросы:

  • Существуют ли другие / более эффективные способы достижения результата из текущего решения?Может быть, группировать и суммировать или отображать / уменьшать?

  • Стоит ли хранить не только идентификаторы пользователей, но и объекты с идентификатором пользователя и количеством подписок?

  • Текущее решение выдаст ошибку, если массив subscriptions не установлен.Есть ли способ справиться с этим?

Большое спасибо за потраченное время на чтение этого длинного поста!

1 Ответ

0 голосов
/ 25 октября 2018

Я бы оставил как идентификатор пользователя, так и количество в массиве подписки и увеличил бы количество, когда у вас есть совпадение с идентификатором пользователя.

Что-то вроде

db.Raffles.update({"subscriptions.id":userid}, {$inc:{"subscriptions.$.count":1}}})

Вы можете получить доступ к коду с помощью запроса ниже.

db.Raffles.find({"subscriptions.id":userid},{"name":1,"ends_at":1,"subscriptions.$":1});
...