探しているのは、位置の$
です。
演算子と「投影」。単一のフィールドの場合は「ドット表記」を使用して必要な配列要素を一致させる必要があり、複数のフィールドの場合は $elemMatch
:
db.products.find(
{ "items.date": "31.08.2014" },
{ "shop": 1, "name":1, "items.$": 1 }
)
または$elemMatch
複数の一致するフィールドの場合:
db.products.find(
{ "items": {
"$elemMatch": { "date": "31.08.2014", "purchasePrice": 1 }
}},
{ "shop": 1, "name":1, "items.$": 1 }
)
ただし、これらは単一の配列要素に対してのみ機能し、1つだけが返されます。条件から複数の配列要素を返す場合は、集計フレームワークを使用したより高度な処理が必要です。
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" }
}}
])
または、アイテムの配列に一意のエントリが含まれているMongoDB 2.6以降、より短い/より高速な形式である可能性があります:
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]
]
}
}}
])
または、 $redact
、しかし少し不自然です:
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$redact": {
"$cond": [
{ "$eq": [ { "$ifNull": [ "$date", "31.08.2014" ] }, "31.08.2014" ] },
"$$DESCEND",
"$$PRUNE"
]
}}
])
より現代的には、$filter
を使用します :
db.products.aggregate([
{ "$match": { "items.date": "31.08.2014" } },
{ "$addFields": {
"items": {
"input": "$items",
"cond": { "$eq": [ "$$this.date", "31.08.2014" ] }
}
}}
])
また、複数の条件がある場合、$elemMatch
および$and
$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 ] }
]
}
}
}}
])
したがって、単一の要素が一致することを常に期待するか、複数の要素が一致することを常に期待するか、そしてどちらのアプローチが優れているかによって異なります。ただし、可能な場合は.find()
メソッドは、他の操作のオーバーヘッドがないため、一般的に高速になります。これは、最後のフォームでは、それほど遅れることはありません。
ちなみに、あなたの「日付」は文字列として表されますが、これは今後あまり良い考えではありません。これらを適切な