我有产品系列。每个产品都包含一系列项目。
> db.products.find().pretty()
{
"_id" : ObjectId("54023e8bcef998273f36041d"),
"shop" : "shop1",
"name" : "product1",
"items" : [
{
"date" : "01.02.2100",
"purchasePrice" : 1,
"sellingPrice" : 10,
"count" : 15
},
{
"date" : "31.08.2014",
"purchasePrice" : 10,
"sellingPrice" : 1,
"count" : 5
}
]
}
那么,请你给我一个建议,我怎样才能查询MongoDB以检索所有只有单个项目的产品,哪个日期等于我传递给查询作为参数的日期。
“31.08.2014”的结果必须是:
{
"_id" : ObjectId("54023e8bcef998273f36041d"),
"shop" : "shop1",
"name" : "product1",
"items" : [
{
"date" : "31.08.2014",
"purchasePrice" : 10,
"sellingPrice" : 1,
"count" : 5
}
]
}
答案 0 :(得分:32)
您正在寻找的是the positional $
运算符和"投影"。对于单个字段,您需要使用"点符号"匹配所需的数组元素,以便使用多个字段$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 }
)
这些只适用于单个数组元素,只返回一个。如果您希望从条件中返回多个数组元素,则需要使用聚合框架进行更高级的处理。
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()
方法通常会更快,因为它缺少其他操作的开销,而最后形式的操作根本不会远远落后于其他操作。
作为旁注,您的"日期"表示为字符串,这不是一个很好的想法。请考虑将这些更改为正确的Date对象类型,这将在未来对您有很大帮助。
答案 1 :(得分:0)
Mongo支持子查询的点表示法。
请参阅:http://docs.mongodb.org/manual/reference/glossary/#term-dot-notation
根据您的驱动程序,您需要以下内容:
db.products.find({"items.date":"31.08.2014"});
请注意,即使您的驱动程序通常不需要,该属性也带有点表示法的引号。
答案 2 :(得分:0)
基于我使用此解决方案的 Neil Lunn's 代码,它自动包含所有第一级键(但如果需要,您也可以排除键):
db.products.find(
{ "items.date": "31.08.2014" },
{ "shop": 1, "name":1, "items.$": 1 }
{ items: { $elemMatch: { date: "31.08.2014" } } },
)
有多个要求:
db.products.find(
{ "items": {
"$elemMatch": { "date": "31.08.2014", "purchasePrice": 1 }
}},
{ items: { $elemMatch: { "date": "31.08.2014", "purchasePrice": 1 } } },
)