Det du letar efter är den positionella $
operatör och "projektion". För ett enstaka fält måste du matcha det obligatoriska arrayelementet med "dot notation", för mer än ett fält använd $elemMatch
:
db.products.find(
{ "items.date": "31.08.2014" },
{ "shop": 1, "name":1, "items.$": 1 }
)
Eller $elemMatch
för mer än ett matchande fält:
db.products.find(
{ "items": {
"$elemMatch": { "date": "31.08.2014", "purchasePrice": 1 }
}},
{ "shop": 1, "name":1, "items.$": 1 }
)
Dessa fungerar dock bara för ett enstaka arrayelement och endast ett kommer att returneras. Om du vill att mer än ett arrayelement ska returneras från dina villkor behöver du mer avancerad hantering med aggregeringsramverket.
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" }
}}
])
Eller möjligen i kortare/snabbare form sedan MongoDB 2.6 där ditt utbud av föremål innehåller unika poster:
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]
]
}
}}
])
Eller möjligen med $redact
, men lite konstruerat:
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$redact": {
"$cond": [
{ "$eq": [ { "$ifNull": [ "$date", "31.08.2014" ] }, "31.08.2014" ] },
"$$DESCEND",
"$$PRUNE"
]
}}
])
Modernare skulle du använda $filter
:
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$addFields": {
"items": {
"input": "$items",
"cond": { "$eq": [ "$$this.date", "31.08.2014" ] }
}
}}
])
Och med flera villkor, $elemMatch
och $and
inom $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 ] }
]
}
}
}}
])
Så det beror bara på om du alltid förväntar dig att ett enskilt element ska matcha eller flera element, och sedan vilket tillvägagångssätt som är bättre. Men där det är möjligt .find()
Metoden kommer i allmänhet att vara snabbare eftersom den saknar overhead för de andra operationerna, som i de sista till formerna inte släpar så långt efter alls.
Som en sidoanteckning representeras dina "datum" som strängar, vilket inte är en särskilt bra idé framöver. Överväg att ändra dessa till korrekt Datum objekttyper, vilket kommer att hjälpa dig mycket i framtiden.