Quello che stai cercando è il $
posizionale
operatore e "proiezione". Per un singolo campo è necessario abbinare l'elemento dell'array richiesto utilizzando la "notazione del punto", per più di un campo utilizzare $elemMatch
:
db.products.find(
{ "items.date": "31.08.2014" },
{ "shop": 1, "name":1, "items.$": 1 }
)
O il $elemMatch
per più di un campo corrispondente:
db.products.find(
{ "items": {
"$elemMatch": { "date": "31.08.2014", "purchasePrice": 1 }
}},
{ "shop": 1, "name":1, "items.$": 1 }
)
Questi funzionano solo per un singolo elemento dell'array e ne verrà restituito solo uno. Se desideri che più di un elemento dell'array venga restituito dalle tue condizioni, hai bisogno di una gestione più avanzata con il framework di aggregazione.
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" }
}}
])
O possibilmente in forma più breve/più veloce da MongoDB 2.6 in cui la tua matrice di elementi contiene voci univoche:
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]
]
}
}}
])
O possibilmente con $redact
, ma un po' forzato:
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$redact": {
"$cond": [
{ "$eq": [ { "$ifNull": [ "$date", "31.08.2014" ] }, "31.08.2014" ] },
"$$DESCEND",
"$$PRUNE"
]
}}
])
Più moderno, useresti $filter
:
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$addFields": {
"items": {
"input": "$items",
"cond": { "$eq": [ "$$this.date", "31.08.2014" ] }
}
}}
])
E con più condizioni, il $elemMatch
e $and
all'interno del $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 ] }
]
}
}
}}
])
Quindi dipende solo dal fatto che ti aspetti sempre che un singolo elemento corrisponda o più elementi, e quindi quale approccio è migliore. Ma dove possibile il .find()
il metodo sarà generalmente più veloce poiché manca il sovraccarico delle altre operazioni, che in quelle ultime ai moduli non è affatto in ritardo.
Come nota a margine, le tue "date" sono rappresentate come stringhe, il che non è una buona idea per il futuro. Prendi in considerazione la possibilità di modificarli in Data tipi di oggetti, che ti saranno di grande aiuto in futuro.