To, czego szukasz, to pozycyjny $
operator i „rzut”. Dla pojedynczego pola musisz dopasować wymagany element tablicy za pomocą „notacji kropkowej”, dla więcej niż jednego pola użyj $elemMatch
:
db.products.find(
{ "items.date": "31.08.2014" },
{ "shop": 1, "name":1, "items.$": 1 }
)
Lub $elemMatch
dla więcej niż jednego pasującego pola:
db.products.find(
{ "items": {
"$elemMatch": { "date": "31.08.2014", "purchasePrice": 1 }
}},
{ "shop": 1, "name":1, "items.$": 1 }
)
Działają one jednak tylko dla jednego elementu tablicy i tylko jeden zostanie zwrócony. Jeśli chcesz, aby więcej niż jeden element tablicy został zwrócony z warunków, potrzebujesz bardziej zaawansowanej obsługi w ramach agregacji.
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" }
}}
])
Lub ewentualnie w krótszej/szybszej formie od MongoDB 2.6, gdzie tablica elementów zawiera unikalne wpisy:
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]
]
}
}}
])
Lub ewentualnie z $redact
, ale trochę wymyślony:
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$redact": {
"$cond": [
{ "$eq": [ { "$ifNull": [ "$date", "31.08.2014" ] }, "31.08.2014" ] },
"$$DESCEND",
"$$PRUNE"
]
}}
])
Bardziej nowoczesny, użyjesz $filter
:
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$addFields": {
"items": {
"input": "$items",
"cond": { "$eq": [ "$$this.date", "31.08.2014" ] }
}
}}
])
A przy wielu warunkach $elemMatch
i $and
w $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 ] }
]
}
}
}}
])
Tak więc zależy to tylko od tego, czy zawsze oczekujesz, że jeden element będzie pasował, czy wiele elementów, a następnie, które podejście jest lepsze. Ale tam, gdzie to możliwe, .find()
Metoda będzie generalnie szybsza, ponieważ nie ma narzutu innych operacji, co w przypadku ostatnich formularzy wcale nie pozostaje w tyle.
Na marginesie, twoje „daty” są reprezentowane jako ciągi, co nie jest dobrym pomysłem na przyszłość. Zastanów się nad ich zmianą na prawidłową Data typy obiektów, które będą bardzo pomocne w przyszłości.