MongoDb - Как вернуть поле вложенного вложенного документа только при использовании агрегации поиска?

Я очень плохо знаком с MongoDb, поэтому я привык к SQL. Прямо сейчас у меня есть две коллекции в моей базе данных:

1) Серия (в которой есть вложенные поддокументы)

2) Рецензия (решили сослаться на поддокумент эпизода, потому что будет много рецензий)

Смотрите эту картинку для лучшего понимания.

Теперь я хочу добиться следующего. Для каждого обзора (два в данном случае) я хочу получить название эпизода.

Я попробовал следующее:

db.review.aggregate([  
   {  
      $lookup:{  
         from:"series",
         localField:"episode",
         foreignField:"seasons.episodes._id",
         as:"episode_entry"
      }
   }
]).pretty()

Проблема в том, что это возвращает (конечно) не только название эпизода, на который есть ссылка, но и документ всего сезона.

Смотрите картинку ниже для моего текущего выхода.

Я не знаю, как этого добиться. Пожалуйста, помогите мне. Я использую Mongo 3.4.9

1 ответ

Решение

Я бы порекомендовал следующую структуру серии, которая разматывает массив сезонов на несколько документов, по одному на каждый сезон.

Это поможет вам вставить / обновить эпизоды напрямую.

Что-то вроде

db.series.insertMany([
  {
    "title": "Sherlock Holmes",
    "nr": 1,
    "episodes": [
      {
        "title": "A Study in Pink",
        "nr": 1
      },
      {
        "title": "The Blind Banker",
        "nr": 2
      }
    ]
  },
  {
    "title": "Sherlock Holmes",
    "nr": 2,
    "episodes": [
      {
        "title": "A Scandal in Belgravia",
        "nr": 1
      },
      {
        "title": "The Hounds of Baskerville",
        "nr": 2
      }
    ]
  }
])

Запрос поиска будет делать что-то вроде этого

episode: { $in: [ episodes._id1, episodes._id2, ... ] }

Из документов

Если поле содержит массив, то оператор $ in выбирает документы, в поле которых содержится массив, который содержит хотя бы один элемент, соответствующий значению в указанном массиве (например, и т. Д.).

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

Так что запрос будет выглядеть

db.review.aggregate([
  {
    "$lookup": {
      "from": "series",
      "localField": "episode",
      "foreignField": "episodes._id",
      "as": "episode_entry"
    }
  },
  {
    "$addFields": {
      "episode_entry": [
        {
          "$arrayElemAt": {
            "$filter": {
              "input": {
                "$let": {
                  "vars": {
                    "season": {
                      "$arrayElemAt": [
                        "$episode_entry",
                        0
                      ]
                    }
                  },
                  "in": "$$season.episodes"
                }
              },
              "as": "result",
              "cond": {
                "$eq": [
                  "$$result._id",
                  "$episode"
                ]
              }
            }
          }
        },
        0
      ]
    }
  }
])
Другие вопросы по тегам