Пн goose получить только указанный c объект из массива или пустой массив, если его нет - PullRequest
2 голосов
/ 05 мая 2020

Итак, у меня есть вопросник модель:

const schema = new mongoose.Schema({
  title: String,
  category: String,
  description: String,
  requirementOption: String,
  creationDate: String,
  questions: [],
  answers: []
})

Как видите, ответы представляют собой массив. Этот массив содержит объект с такой структурой

{
  "participantEmail": "someEmail@email.email"      
  "currentIndex": 14,
  ...
}

Теперь я хочу получить специальную c анкету по идентификатору, но в массиве ответов я хочу указать только c адрес электронной почты участника. Таким образом, массив ответов должен иметь либо один элемент, либо ни одного элемента. Но я не хочу получать результат null, если в массиве ответов нет такого письма.

Я понимаю, как получить этот конкретный c элемент из массива с помощью этого запроса:

dbModel.findOne({_id: id, 'answers': {$elemMatch: {participantEmail: "someEmail@email.com"}}}, {'answers.$': 1}).exec();

И если это электронное письмо существует в массиве ответов, я получу следующее:

 "data": {
    "questionnaireForParticipant": {
      "id": "5d9ca298cba039001b916c55",
      "title": null,
      "category": null,
      "creationDate": null,
      "description": null,
      "questions": null,
      "answers": [
        {
          "participantEmail": "someEmail@email.com",
          ....
         }

    }
  }

Но если этого электронного письма нет в массиве ответов, я получу только null. Также я хотел бы получить title и category и все остальные поля. Но я не могу найти способ сделать это.

Ответы [ 3 ]

1 голос
/ 05 мая 2020

Принятый ответ правильный, но если вы используете mon goose, как я, вот как вы должны написать принятый ответ на запрос:

      dbModel.aggregate([
          { 
            $match: { "_id": mongoose.Types.ObjectId("5a934e000102030405000000") } 
          }]).addFields({
            answers: {
              $filter: {
                input: "$answers",
                  cond: { $eq: [ "$$this.participantEmail", "someEmail@email.com" ] }
              }
            }
          }).exec();
1 голос
/ 05 мая 2020

Так как у вас есть это условие 'answers': {$elemMatch: {participantEmail: "someEmail@email.com"}} в части фильтра .findOne() - Если для данного _id документа нет элементов в массиве answers. participantEmail, совпадающих с входным значением "someEmail@email.com", то .findOne() вернет null в качестве вывода. Поэтому, если вы хотите вернуть документ независимо от того, существует ли соответствующий элемент в массиве answers или нет, попробуйте запрос ниже:

db.collection.aggregate([
  {
    $match: { "_id": ObjectId("5a934e000102030405000000") }
  },
  /** addFields will re-create an existing field or will create new field if there is no field with same name */
  {
    $addFields: {
      answers: {
        $filter: { // filter will result in either [] or array with matching elements
          input: "$answers",
          cond: { $eq: [ "$$this.participantEmail", "someEmail@email.com" ] }
        }
      }
    }
  }
])

Тест: mongoplayground

Ссылка: конвейер агрегации

Примечание: Мы использовали агрегацию, так как вы хотели вернуть либо answers массив с согласованным элементом или пустой массив. Также вы можете использовать $project вместо $addFields для преобразования вывода по вашему желанию.

0 голосов
/ 05 мая 2020

В этом примере входной документ :

{
  _id: 1,
  title: "t-1",
  category: "cat-abc",
  creationDate: ISODate("2020-05-05T07:01:09.853Z"),
  questions: [ ],
  answers: [
      { participantEmail: "someEmail@email.email", currentIndex: 14 }
  ]
}

И с этим запрос :

EMAIL_TO_MATCH = "someEmail@email.email"

db.questionnaire.findOne( 
  { _id: 1 }, 
  { title: 1, category: 1, answers: { $elemMatch: { participantEmail: EMAIL_TO_MATCH } } } 
)

Запрос возвращает (когда answers.participantEmail соответствует):

{
        "_id" : 1,
        "title" : "t-1",
        "category" : "cat-abc",
        "answers" : [
                {
                        "participantEmail" : "someEmail@email.email",
                        "currentIndex" : 12
                }
        ]
}

И, когда answers.participantEmail не соответствует , или если массив amswers равен пустой , результат будет:

{ "_id" : 1, "title" : "t-1", "category" : "cat-abc" }


ПРИМЕЧАНИЕ : $ elemMatch в приведенном выше запросе используется оператор проекция .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...