Как заполнить MongoDB без мангуста?

Я работаю над университетским проектом, и мне нужно заполнить массив объектов идентификаторами ObjectId, но я не могу использовать mongoose в своем проекте. У меня есть две коллекции - тематическая и учебная программа.

Пример документа StudyProgram:

{
  _id: ObjectId('111'),
  name: "Study program 1"
  description: "Lorem ipsum dolor sit amet",
  language: "en",
  subjects: [
    {
      id: ObjectId('222'),
      optionality: "selective",
      credits: 8,
    },
    {
      id: ObjectId('333'),
      optionality: "selective",
      credits: 5
    },
  ],
}

Примеры тематических документов:

{
  _id: ObjectId('222'),
  name: "Subject A",
  description: "Subject A description.",
},
{
  _id: ObjectId('333'),
  name: "Subject B",
  description: "Subject B description.",
}

Мне нужно заполнить объекты в массиве subjects соответствующими документами из предметной коллекции на основе id. В основном то, что я ищу, это этот результат:

{
  _id: ObjectId('111'),
  name: "Study program 1"
  description: "Lorem ipsum dolor sit amet",
  language: "en",
  subjects: [
    {
      
      _id: ObjectId('222'),
      name: "Subject A",
      description: "Subject A description.",
      optionality: "selective",
      credits: 8,
    },
    {
      _id: ObjectId('333'),
      name: "Subject B",
      description: "Subject B description.",
      optionality: "selective",
      credits: 5
    },
  ],
}

До сих пор я пытался использовать следующий $lookup:

{
  $lookup: {
    from: "subject",
    localField: "subjects.id",
    foreignField: "_id",
    as: "subjects",
  }
}

Но это удаляет атрибуты optionality и credits. Есть ли способ добиться этого без использования мангуста? Спасибо.

Как использовать API парсинга квитанций с помощью JavaScript за 5 минут?
Как использовать API парсинга квитанций с помощью JavaScript за 5 минут?
В этом руководстве вы узнаете, как использовать API парсинга квитанций за 5 минут с помощью JavaScript. Eden AI предоставляет простой и удобный для...
Хук useOnClickOutside в ReactJS
Хук useOnClickOutside в ReactJS
Как разработчик ReactJS, вы, возможно, сталкивались с ситуацией, когда вам нужно закрыть модальное или выпадающее меню, когда кто-то щелкает за его...
Хуки (часть-2) - useEffect
Хуки (часть-2) - useEffect
Хук useEffect - один из самых мощных и универсальных инструментов в арсенале разработчика React. Он позволяет вам управлять побочными эффектами в...
Простое руководство по тестированию взаимодействия с пользователем с помощью библиотеки тестирования React
Простое руководство по тестированию взаимодействия с пользователем с помощью библиотеки тестирования React
В предыдущем посте я показал вам на примерах, как писать базовые тесты в React. Важнейшей частью пользовательского интерфейса приложений является...
Как конвертировать HTML в PDF с помощью jsPDF
Как конвертировать HTML в PDF с помощью jsPDF
В этой статье мы рассмотрим, как конвертировать HTML в PDF с помощью jsPDF. Здесь мы узнаем, как конвертировать HTML в PDF с помощью javascript.
Создайте титры как в звездных войнах с помощью CSS и Javascript
Создайте титры как в звездных войнах с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
1
0
170
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот один из способов сделать это.

db.studyProgram.aggregate([
  {
    "$lookup": {
      "from": "subject",
      "localField": "subjects.id",
      "foreignField": "_id",
      "as": "subjectDocs"
    }
  },
  {
    "$set": {
      "subjects": {
        "$map": {
          "input": "$subjects",
          "as": "subject",
          "in": {
            "$mergeObjects": [
              {
                "$first": {
                  "$filter": {
                    "input": "$subjectDocs",
                    "as": "doc",
                    "cond": {"$eq": ["$$doc._id", "$$subject.id"]}
                  }
                }
              },
              {
                "optionality": "$$subject.optionality",
                "credits": "$$subject.credits"
              }
            ]
          }
        }
      },
      "subjectDocs": "$$REMOVE"
    }
  }
])

Попробуйте на mongoplayground.net.

Если "$first" недоступен, попросите вашего системного администратора обновить MongoDB! До тех пор это, вероятно, будет работать.

db.studyProgram.aggregate([
  {
    "$lookup": {
      "from": "subject",
      "localField": "subjects.id",
      "foreignField": "_id",
      "as": "subjectDocs"
    }
  },
  {
    "$set": {
      "subjects": {
        "$map": {
          "input": "$subjects",
          "as": "subject",
          "in": {
            "$mergeObjects": [
              {
                "$arrayElemAt": [
                  {
                    "$filter": {
                      "input": "$subjectDocs",
                      "as": "doc",
                      "cond": {"$eq": ["$$doc._id", "$$subject.id"]}
                    }
                  },
                  0
                ]
              },
              {
                "optionality": "$$subject.optionality",
                "credits": "$$subject.credits"
              }
            ]
          }
        }
      },
      "subjectDocs": "$$REMOVE"
    }
  }
])

Попробуйте на mongoplayground.net.

Большое спасибо, я попробовал это на mongoplayground, и это работает. Однако, когда я использую его в своем проекте, я получаю сообщение об ошибке: «Нераспознанное выражение «$ first»». Я полагаю, это потому, что я использую Mongo версии 4.11.0, а $first недоступен в этой версии. Есть ли другой оператор, который я могу использовать вместо этого?

Marek Balvín 21.11.2022 22:06

@MarekBalvín Да, я вижу, "$first" доступен только в "$group" с этой версией. Я обновил конвейер агрегации с помощью "$arrayElemAt". Смотрите обновленный ответ.

rickhg12hs 21.11.2022 23:10

Другие вопросы по теме