O que você está procurando é o
$
posicional
operador e "projeção". Para um único campo, você precisa corresponder ao elemento de matriz necessário usando "notação de ponto", para mais de um campo, use $elemMatch
:db.products.find(
{ "items.date": "31.08.2014" },
{ "shop": 1, "name":1, "items.$": 1 }
)
Ou o
$elemMatch
para mais de um campo correspondente:db.products.find(
{ "items": {
"$elemMatch": { "date": "31.08.2014", "purchasePrice": 1 }
}},
{ "shop": 1, "name":1, "items.$": 1 }
)
Eles funcionam apenas para um único elemento de matriz e apenas um será retornado. Se você quiser que mais de um elemento de matriz seja retornado de suas condições, precisará de um tratamento mais avançado com a estrutura de agregação.
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$unwind": "$items" },
{ "$match": { "items.date": "31.08.2014" } },
{ "$group": {
"_id": "$_id",
"shop": { "$first": "$shop" },
"name": { "$first": "$name" },
"items": { "$push": "$items" }
}}
])
Ou possivelmente de forma mais curta/rápida desde o MongoDB 2.6, onde sua matriz de itens contém entradas exclusivas:
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$project": {
"shop": 1,
"name": 1,
"items": {
"$setDifference": [
{ "$map": {
"input": "$items",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el.date", "31.08.2014" ] },
"$$el",
false
]
}
}},
[false]
]
}
}}
])
Ou possivelmente com
$redact
, mas um pouco artificial:db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$redact": {
"$cond": [
{ "$eq": [ { "$ifNull": [ "$date", "31.08.2014" ] }, "31.08.2014" ] },
"$$DESCEND",
"$$PRUNE"
]
}}
])
Mais moderno, você usaria
$filter
:db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$addFields": {
"items": {
"input": "$items",
"cond": { "$eq": [ "$$this.date", "31.08.2014" ] }
}
}}
])
E com várias condições, o
$elemMatch
e $and
dentro do $filter
:db.products.aggregate([
{ "$match": {
"$elemMatch": { "date": "31.08.2014", "purchasePrice": 1 }
}},
{ "$addFields": {
"items": {
"input": "$items",
"cond": {
"$and": [
{ "$eq": [ "$$this.date", "31.08.2014" ] },
{ "$eq": [ "$$this.purchasePrice", 1 ] }
]
}
}
}}
])
Portanto, depende apenas se você sempre espera que um único elemento corresponda ou vários elementos e, em seguida, qual abordagem é melhor. Mas sempre que possível o
.find()
O método geralmente será mais rápido, pois não possui a sobrecarga das outras operações, que nessas últimas formas não ficam tão atrasadas. Como uma nota lateral, suas "datas" são representadas como strings, o que não é uma boa ideia daqui para frente. Considere alterá-los para a Data adequada tipos de objetos, que o ajudarão muito no futuro.