mongodb 如何在MongoDB集合中查找符合给定条件的文档和单个子文档

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25586901/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:08:38  来源:igfitidea点击:

How to find document and single subdocument matching given criterias in MongoDB collection

mongodbmongodb-queryaggregation-framework

提问by evgeniy44

I have collection of products. Each product contains array of items.

我有产品系列。每个产品都包含一系列项目。

> 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
            }
    ]
}

So, can you please give me an advice, how I can query MongoDB to retrieve all products with only single item which date is equals to the date I pass to query as parameter.

那么,请您给我一个建议,我如何查询 MongoDB 以检索所有产品,其中只有一个项目的日期等于我作为参数传递给查询的日期。

The result for "31.08.2014" must be:

“31.08.2014”的结果必须是:

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

回答by Neil Lunn

What you are looking for is the positional $operator and "projection". For a single field you need to match the required array element using "dot notation", for more than one field use $elemMatch:

您正在寻找的是位置$运算符和“投影”。对于单个字段,您需要使用“点表示法”匹配所需的数组元素,对于多个字段使用$elemMatch

db.products.find(
    { "items.date": "31.08.2014" },
    { "shop": 1, "name":1, "items.$": 1 }
)

Or the $elemMatchfor more than one matching field:

或者$elemMatch对于多个匹配字段:

db.products.find(
    { "items":  { 
        "$elemMatch": { "date": "31.08.2014",  "purchasePrice": 1 }
    }},
    { "shop": 1, "name":1, "items.$": 1 }
)

These work for a single array element only though and only one will be returned. If you want more than one array element to be returned from your conditions then you need more advanced handling with the aggregation framework.

这些仅适用于单个数组元素,并且只会返回一个。如果您希望从您的条件中返回多个数组元素,那么您需要使用聚合框架进行更高级的处理。

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" }
    }}
])

Or possibly in shorter/faster form since MongoDB 2.6 where your array of items contains unique entries:

或者可能是自 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]
            ]
        }
    }}
])

Or possibly with $redact, but a little contrived:

或者可能与$redact,但有点做作:

db.products.aggregate([
    { "$match": { "items.date": "31.08.2014" } },
    { "$redact": {
        "$cond": [
             { "$eq": [ { "$ifNull": [ "$date", "31.08.2014" ] }, "31.08.2014" ] },
             "$$DESCEND",
             "$$PRUNE"
         ]
    }}
])

More modern, you would use $filter:

更现代的,你会使用$filter

db.products.aggregate([
  { "$match": { "items.date": "31.08.2014" } },
  { "$addFields": {
    "items": {
      "input": "$items",
      "cond": { "$eq": [ "$$this.date", "31.08.2014" ] }
    }
  }}
])

And with multiple conditions, the $elemMatchand $andwithin the $filter:

并且在多个条件下,$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 ] }
        ]
      }
    }
  }}
])

So it just depends on whether you always expect a single element to match or multiple elements, and then which approach is better. But where possible the .find()method will generally be faster since it lacks the overhead of the other operations, which in those last to forms does not lag that far behind at all.

因此,这仅取决于您始终期望匹配单个元素还是多个元素,然后哪种方法更好。但是在可能的情况下,该.find()方法通常会更快,因为它没有其他操作的开销,在那些最后的表单中,它根本不会落后那么远。

As a side note, your "dates" are represented as strings which is not a very good idea going forward. Consider changing these to proper Dateobject types, which will greatly help you in the future.

作为旁注,您的“日期”表示为字符串,这不是一个很好的主意。考虑将这些更改为正确的Date对象类型,这将在将来对您有很大帮助。

回答by Jared Alessandroni

Mongo supports dot notation for sub-queries.

Mongo 支持子查询的点表示法。

See: http://docs.mongodb.org/manual/reference/glossary/#term-dot-notation

请参阅:http: //docs.mongodb.org/manual/reference/glossary/#term-dot-notation

Depending on your driver, you want something like:

根据您的驱动程序,您需要以下内容:

db.products.find({"items.date":"31.08.2014"});

Note that the attribute is in quotes for dot notation, even if usually your driver doesn't require this.

请注意,该属性用引号括起来表示点符号,即使您的驱动程序通常不需要这样做。