Запрос Mongo на нескольких полях суб-документа

Предположим, у меня есть такая коллекция:

{ "arr" : [ { "name" : "a", "num" : 1 }, { "name" : "a", "num" : 2 } ] },
{ "arr" : [ { "name" : "b", "num" : 1 }, { "name" : "a", "num" : 2 } ] },
{ "arr" : [ { "name" : "b", "num" : 1 }, { "name" : "b", "num" : 2 } ] }

и я хочу найти все документы, у которых arr есть вложенный документ с name = "b" и num = 2.

Если я сделаю такой запрос:

db.collection.find({
    $and: [
        { "arr.name": "b" },
        { "arr.num": 2 }
    ]
});

он вернет все документы в коллекции, потому что каждый из них содержит вложенный документ с name из «b» или num из 2.

Я тоже пробовал это:

db.collection.find({
    arr: [
        { "name": "b", "num": 2 }
    ]
});

который не вызывает ошибок, но не возвращает никаких результатов.

Как вы запрашиваете несколько полей вложенного документа в MongoDB?


person Greg    schedule 13.01.2015    source источник


Ответы (1)


Именно для этого и предназначен оператор $elemMatch, даже если он часто используется неправильно. По сути, он выполняет условия запроса для каждого элемента «внутри» массива. Все аргументы MongoDB являются операцией «и», если явно не указано иное:

db.collection.find({ "arr": { "$elemMatch": { "name": "b", "num": 2  } } })

Вы, вероятно, также захотите «спроецировать» и здесь, если ожидаете только совпадающее поле, а не весь документ:

db.collection.find(
    { "arr": { "$elemMatch": { "name": "b", "num": 2  } } },
    { "arr.$": 1 }
)

Наконец, чтобы объяснить, почему ваша вторая попытка не работает, этот запрос:

db.collection.find({
    "arr": [
        { "name": "b", "num": 2 }
    ]
})

Ничего не соответствует, потому что нет фактического документа, в котором "arr" содержит единственный элемент, точно соответствующий вашим условиям.

Ваш первый пример не удался ..:

db.collection.find({
    $and: [
        { "arr.name": "b" },
        { "arr.num": 2 }
    ]
});

Потому что есть несколько элементов массива, которые удовлетворяют условиям, и это не просто считается, что оба условия применяются к одному и тому же элементу. Это то, что добавляет $elemMatch, и когда вам нужно сопоставить более одного условия, вы можете использовать это здесь.

person Neil Lunn    schedule 13.01.2015
comment
Очень полезный и полный ответ, извините за невозможность проголосовать дважды. Спасибо, Нил! - person Moppo; 13.10.2015