Предположим, у вас есть следующие документы в моей коллекции:
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}
Сделать запрос:
db.test.find({"shapes.color": "red"}, {"shapes.color": 1})
Или
db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})
Возвращает соответствующий документ (Документ 1) , но всегда со всеми элементами массива в shapes
:
{ "shapes":
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}
Однако я хотел бы получить документ (Документ 1) только с массивом, который содержит color=red
:
{ "shapes":
[
{"shape": "circle", "color": "red"}
]
}
Как я могу это сделать?
aggregate
.db.test.find({}, {shapes: {$elemMatch: {color: "red"}}});
Новая структура агрегации в MongoDB 2.2+ предоставляет альтернативу Map / Reduce.
$unwind
Оператор может быть использован для разделения вашегоshapes
массива в поток документов , которые могут быть отмечены:Результаты в:
источник
$elemMatch
есть еще один вариант. На самом деле я попал сюда через вопрос группы Google, где $ elemMatch не будет работать, потому что он возвращает только первое совпадение для каждого документа.{ $project : { shapes : 1 } }
- что, похоже, сработало и было бы полезно, если бы вложенные документы были большими, а вы просто хотели просмотретьshapes
значения ключей.Другой интересный способ - использовать $ redact , который является одной из новых функций агрегирования в MongoDB 2.6 . Если вы используете 2.6, вам не нужен $ unwind, который может вызвать проблемы с производительностью, если у вас большие массивы.
$redact
«ограничивает содержание документов на основе информации, хранящейся в самих документах» . Так что он будет работать только внутри документа . Он в основном сканирует ваш документ сверху донизу и проверяет, соответствует ли оно вашемуif
условию$cond
, если оно совпадает, или он будет сохранять content ($$DESCEND
) или remove ($$PRUNE
).В приведенном выше примере сначала
$match
возвращается весьshapes
массив, а $ redact сокращает его до ожидаемого результата.Обратите внимание, что
{$not:"$color"}
это необходимо, поскольку он также будет сканировать верхний документ, а если$redact
не найдетcolor
поле на верхнем уровне, он вернется,false
что может привести к удалению всего документа, который нам не нужен.источник
$match
качестве своей первой совокупной стадииПараметр селектора поля ограничен полными свойствами. Его нельзя использовать для выбора части массива, только всего массива. Я пытался использовать $ позиционный оператор , но это не сработало.
Самый простой способ - просто отфильтровать фигуры в клиенте .
Если вам действительно нужен правильный вывод непосредственно из MongoDB, вы можете использовать map-lower для фильтрации фигур.
источник
Лучше сделать запрос в соответствующем элементе массива, используя
$slice
его, чтобы вернуть значимый объект в массив.$slice
полезно, когда вы знаете индекс элемента, но иногда вы хотите, чтобы какой-либо элемент массива соответствовал вашим критериям. Вы можете вернуть соответствующий элемент с$
оператором.источник
ВЫХОДЫ
источник
Синтаксис для поиска в mongodb:
и второй запрос, который вы написали, то есть
в этом вы использовали
$elemMatch
оператор в части запроса, тогда как, если вы используете этот оператор в части проекции, вы получите желаемый результат. Вы можете записать свой запрос какЭто даст вам желаемый результат.
источник
"shapes.color":"red"
в параметре запроса (первый параметр метода find) нет необходимости. Вы можете заменить его{}
и получить те же результаты.Спасибо JohnnyHK .
Здесь я просто хочу добавить более сложное использование.
источник
Вам просто нужно запустить запрос
вывод этого запроса
как вы и ожидали, он даст точное поле из массива, соответствующее цвету: «красный».
источник
вместе с $ project будет более уместно, если другие подходящие элементы будут объединены с другими элементами в документе.
источник
Точно так же вы можете найти для нескольких
источник
$match
сократить пространство, затем$filter
сохранить то, что вы хотите, перезаписав поле ввода (используйте вывод$filter
поля on,shapes
чтобы$project
вернуться кshapes
. Примечание о стиле: лучше не использовать имя поля какas
аргумент , так как это может привести к путанице позже$$shape
и$shape
я предпочитаю.zz
какas
поле , потому что он действительно выделяется.источник
Используйте функцию агрегации и
$project
для получения конкретного поля объекта в документерезультат:
источник
Хотя вопрос был задан 9,6 года назад, это оказало огромную помощь многим людям, и я был одним из них. Спасибо всем за все ваши вопросы, советы и ответы. Подняв один из ответов здесь ... Я обнаружил, что следующий метод также может быть использован для проецирования других полей в родительском документе. Это может быть полезно для кого-то.
Для следующего документа необходимо было выяснить, имеет ли сотрудник (emp # 7839) историю отпусков, установленную на 2020 год. История отпусков реализована как встроенный документ в родительском документе Employee.
источник