我收集了很多产品.每个产品都包含一系列项目.

> 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来检索所有产品,其中只有一个项目的日期等于我作为参数传递给查询的日期.

"2014年8月31日"的结果必须是:

    {
    "_id" : ObjectId("54023e8bcef998273f36041d"),
    "shop" : "shop1",
    "name" : "product1",
    "items" : [
            {
                    "date" : "31.08.2014",
                    "purchasePrice" : 10,
                    "sellingPrice" : 1,
                    "count" : 5
            }
    ]
}

推荐答案

你要找的是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开始的更短/更快的形式,在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" ] }
    }
  }}
])

在多个条件下,$filter中的$elemMatch$and:

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种对象类型,这将在很大程度上帮助您在future .

Mongodb相关问答推荐

在MongoDB中使用explain()和查询时缺少winningPlan''''

MongoDB Aggregate-如何在条件中替换字符串中的变量

在MogoDB中按时间间隔分组、统计文档和获取间隔时间

MongoDB$unionWith,如何 Select 特定文档

MongoDb聚合查询问题

Mongoose 查询以获取内部数组和该内部数组中的特定元素

mongo如何通过聚合加载嵌套文档

Mongoose $inc 枚举验证失败

mongoose中的 required是什么意思?

更新 mongodb 文档中的特定字段

mongodb 模式设计命名约定

$elemMatch 的 MongoDB 索引

MongoDB - 投影一个并不总是存在的字段

如何使用 MongoDB 以编程方式预拆分基于 GUID 的分片键

MongoDB 范围查询中 $lt 和 $gt 的顺序

有人在 Google App Engine 上try 过 MongoDB 吗?

Mongodb - 如何在多个字段中查找字符串?

在mongoose中查询虚拟属性

MongoDb 连接被拒绝

MongoDB InsertMany 与 BulkWrite