Bezdepbonusu7Программирование: статьи и ответы

Вопрос

MongoDB: несколько $elemMatch

Автор вопроса: gevraОтветов: 1

У меня есть документы MongoDB, структурированные следующим образом:

{_id: ObjectId("53d760721423030c7e14266f"),
fruit: 'apple',
vitamins: [
    {
     _id: 1,
     name: 'B7',
     usefulness: 'useful',
     state: 'free',
    }
    {
     _id: 2,
     name: 'A1',
     usefulness: 'useful',
     state: 'free',
    }
    {
     _id: 3,
     name: 'A1',
     usefulness: 'useful',
     state: 'non_free',
    }
  ]
}
{_id: ObjectId("53d760721423030c7e142670"),
fruit: 'grape',
vitamins: [
    {
     _id: 4,
     name: 'B6',
     usefulness: 'useful',
     state: 'free',
    }
    {
     _id: 5,
     name: 'A1',
     usefulness: 'useful',
     state: 'non_free',
    }
    {
     _id: 6,
     name: 'Q5',
     usefulness: 'non_useful',
     state: 'non_free',
    }
  ]
}

Я хочу запросить и получить все фрукты, которые имеют как {name: 'A1', state: 'non_free'}, так и {name: 'B7', state: 'free'}. В худшем случае я хочу, по крайней мере, подсчитать эти записи, если их получение невозможно, и если существует эквивалентный код для pymongo, чтобы знать, как его написать.

В данном примере я хочу получить только первый (яблочный) документ.

Если я использую $elemMatch, он работает только для одного условия, но не для обоих. Например. если я запрошу find({'vitamins': {'$elemMatch': {'name': 'A1', 'state': 'non_free'}, '$elemMatch': {'name': 'B7', 'state': 'free'}}}), он получит все фрукты с {'name': 'B7', 'state': 'free'}.

mongodbpymongo

Ответы

Ответ 1 · рейтинг 31 · Philipp

В этом случае вы можете использовать $and-operator .

Попробуйте этот запрос:

find({
    $and: [
         {'vitamins': {'$elemMatch': {'name': 'A1', 'state': 'non_free'} } },
         {'vitamins': {'$elemMatch': {'name': 'B7', 'state': 'free'} } }
    ]
});

Чтобы объяснить, почему вы получили только результат, соответствующий второму критерию: объекты внутри каждого {}, который вы передаете в MongoDB, представляют собой пары ключ/значение. Каждый ключ может существовать только один раз для каждого объекта. Когда вы пытаетесь дважды присвоить значение одной и той же клавише, второе назначение переопределит первое. В вашем случае вы присвоили ключу $elemMatch два разных значения в одном и том же объекте, поэтому первое было проигнорировано. Запрос, который фактически поступил в MongoDB, был просто find({'vitamins': {'$elemMatch': {'name': 'B7', 'state': 'free'}}}).

Всякий раз, когда вам нужно дважды применить один и тот же оператор к одной и той же клавише, вам нужно использовать $or или $and.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы