简体   繁体   English

如何仅检索 MongoDB 中嵌入文档数组的子集?

[英]How to retrieve only a subset of an array of embedded documents in MongoDB?

I am new to MongoDB and I am having trouble retrieving only a subset of an array of embedded documents.我是 MongoDB 的新手,我无法仅检索嵌入式文档数组的子集。 For instance, I have the following documents:例如,我有以下文件:

{
   "_id": "Stock1",
   "data": [{"value": 10.0, "date": "2000-01-01T00:00:00.000Z"},
            {"value": 12.0, "date": "2010-01-01T00:00:00.000Z"},
            {"value": 14.0, "date": "2020-01-01T00:00:00.000Z"}]
},
{
   "_id": "Stock2",
   "data": [{"value": 10.0, "date": "2000-01-01T00:00:00.000Z"},
            {"value": 8.0, "date": "2010-01-01T00:00:00.000Z"},
            {"value": 6.0, "date": "2020-01-01T00:00:00.000Z"}]
},
{
   "_id": "Stock3",
   "data": [{"value": 10.0, "date": "2000-01-01T00:00:00.000Z"},
            {"value": 10.0, "date": "2010-01-01T00:00:00.000Z"},
            {"value": 10.0, "date": "2020-01-01T00:00:00.000Z"}]
}

And I would like to retrieve data between date 2010-01-01 and 2020-01-01 (included) of "Stock1" and "Stock3", ie I would like to end up with this:我想检索“Stock1”和“Stock3”的date 2010-01-01 和 2020-01-01(包括)之间的data ,即我想得到这个:

{
   "_id": "Stock1",
   "data": [{"value": 12.0, "date": "2010-01-01T00:00:00.000Z"},
            {"value": 14.0, "date": "2020-01-01T00:00:00.000Z"}]
},
{
   "_id": "Stock3",
   "data": [{"value": 10.0, "date": "2010-01-01T00:00:00.000Z"},
            {"value": 10.0, "date": "2020-01-01T00:00:00.000Z"}]
}

I have tried the find command:我试过find命令:

{"_id": {$in: ["Stock1", "Stock3"]}, "data.date": {$gte: ISODate('2010-01-01'), $lte: ISODate('2020-01-01')}}

But I am retrieving all dates, which is undesirable.但我正在检索所有日期,这是不可取的。

I am aware of the aggregate command but I am unsure of how to construct the pipeline.我知道aggregate命令,但我不确定如何构建管道。 Can someone pinpoint me on how I should proceed?有人可以指出我应该如何进行吗?

Any help would be greatly appreciated!任何帮助将不胜感激!

Solution 1解决方案 1

  1. $unwind - Descontruct data array to documents. $unwind - 将data数组解构为文档。
  2. $match - Filter based on id and date range for data.date . $match - 根据data.dateid和日期范围进行过滤。
  3. $group - Group by id (Reverse for Step 1). $group - 按id分组(与第 1 步相反)。
db.collection.aggregate([
  {
    $unwind: "$data"
  },
  {
    $match: {
      $expr: {
        $and: [
          {
            $in: [
              "$_id",
              [
                "Stock1",
                "Stock3"
              ]
            ]
          },
          {
            $gte: [
              {
                $toDate: "$data.date"
              },
              ISODate("2010-01-01")
            ]
          },
          {
            $lte: [
              {
                $toDate: "$data.date"
              },
              ISODate("2020-01-01")
            ]
          }
        ]
      }
    }
  },
  {
    $group: {
      "_id": "$_id",
      "data": {
        $push: "$data"
      }
    }
  }
])

Sample Solution 1 on Mongo Playground Mongo Playground 上的示例解决方案 1


Solution 2解决方案 2

  1. $match - Filter document(s) based on _id . $match - 根据_id过滤文档。
  2. $project - Display the document with $filter data array. $project - 显示带有$filter数据数组的文档。
db.collection.aggregate([
  {
    $match: {
      "_id": {
        $in: [
          "Stock1",
          "Stock3"
        ]
      }
    }
  },
  {
    $project: {
      "_id": 1,
      "data": {
        "$filter": {
          "input": "$data",
          "cond": {
            "$and": [
              {
                $gte: [
                  {
                    $toDate: "$$this.date"
                  },
                  ISODate("2010-01-01")
                ]
              },
              {
                $lte: [
                  {
                    $toDate: "$$this.date"
                  },
                  ISODate("2020-01-01")
                ]
              }
            ]
          }
        }
      }
    }
  }
])

Sample Solution 2 on Mongo Playground Mongo Playground 上的示例解决方案 2

You can use $elemMatch :您可以使用$elemMatch

{"_id": {$in: ["Stock1", "Stock3"]}, "data":{$elemMatch:{date: {$gte: ISODate('2010-01-01'), $lte: ISODate('2020-01-01')}}}}

A Single Nested Document Meets Multiple Query Conditions on Nested Fields单个嵌套文档满足嵌套字段的多个查询条件

Use $elemMatch operator to specify multiple criteria on an array of embedded documents such that at least one embedded document satisfies all the specified criteria.使用 $elemMatch 运算符对一组嵌入文档指定多个条件,以便至少一个嵌入文档满足所有指定条件。

Source: https://docs.mongodb.com/manual/tutorial/query-array-of-documents/资料来源: https://docs.mongodb.com/manual/tutorial/query-array-of-documents/

To avoid $unwind and $group you can use $filter in an aggregate query like this:为了避免$unwind$group你可以在这样的聚合查询中使用$filter

db.collection.aggregate([
  {
    "$match": {
      "_id": {
        "$in": ["Stock1","Stock3"]
      }
    }
  },
  {
    "$project": {
      "data": {
        "$filter": {
          "input": "$data",
          "as": "d",
          "cond": {
            "$and": [
              {
                "$gte": [{"$toDate": "$$d.date"},ISODate("2010-01-01")]
              },
              {
                "$lte": [{"$toDate": "$$d.date"},ISODate("2020-01-01")]
              }
            ]
          }
        }
      }
    }
  }
])

Example here这里的例子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM