如何在MongoDB中同时查询两个数组?

How to query on two arrays at the same time in MongoDB?

我有以下文档,其中每个文档都有字段 valuesdates,它们是数组。这些数组在每个文档中始终具有相同的大小,这意味着 dates 中的每个值对应于 values:

中的一个值
[
  {
    _id: "Stock1",
    values: [
      1,
      2,
      3
    ],
    dates: [
      ISODate("2000-01-01"),
      ISODate("2010-01-01"),
      ISODate("2020-01-01")
    ]
  },
  {
    _id: "Stock2",
    values: [
      4,
      5,
    ],
    dates: [
      ISODate("2000-01-01"),
      ISODate("2010-01-01")
    ]
  },
  {
    _id: "Stock3",
    values: [
      7,
      8,
      9
    ],
    dates: [
      ISODate("2000-01-01"),
      ISODate("2010-01-01"),
      ISODate("2020-01-01")
    ]
  }
]

我想查询我的文档,以便在 dates“2010-01-01”和 dates“2020-01-01”(包括)之间获得 values仅适用于“Stock1”和“Stock3”,即我想以:

[
  {
    _id: "Stock1",
    values: [
      2,
      3
    ],
    dates: [
      ISODate("2010-01-01"),
      ISODate("2020-01-01")
    ]
  },
  {
    _id: "Stock3",
    values: [
      8,
      9
    ],
    dates: [
      ISODate("2010-01-01"),
      ISODate("2020-01-01")
    ]
  }
]

目前,我正在做以下事情:

db.collection.aggregate([
  {
    $match: {
      _id: {
        $in: [
          "Stock1",
          "Stock3"
        ]
      }
    }
  },
  {
    $unwind: {
      path: "$dates",
      includeArrayIndex: "date_index"
    }
  },
  {
    $match: {
      dates: {
        $gte: ISODate("2010-01-01"),
        $lte: ISODate("2020-01-01")
      }
    }
  },
  {
    $unwind: {
      path: "$values",
      includeArrayIndex: "value_index"
    }
  },
  {
    $match: {
      $expr: {
        $eq: [
          "$date_index",
          "$value_index"
        ]
      }
    }
  },
  {
    $project: {
      date_index: 0,
      value_index: 0
    }
  }
])

但我还没到那一步。此外,管道看起来很长且次优。有更好的方法吗?最后,我首先在 dates 上使用 unwind,然后在 values 上再次使用 unwind 之前进行过滤:这是为了避免管道中的许多文档太大,因为数组 datesvalues 可能很大。

如有任何帮助,我们将不胜感激!

查询

  • 匹配只保留"Stock1","Stock3"
  • 筛选日期 (range (size "$dates")) 的索引,以仅获取日期在 [2010-2020]
  • 范围内的元素的索引
  • 2 映射以从 datesvalues
  • 中获取那些过滤后的索引

*我们可以像 1 个 reduce 一样完成所有操作,但它会嵌套且代码更复杂,而且 $concatArrays 很慢,将数组减少到 array.The 不是一个好主意,下面更简单和甚至可以用于非常大的数组。

PlayMongo

aggregate(
[{"$match": {"_id": { "$in": ["Stock1","Stock3"]}}}
 {"$set": 
    {"indexes": 
      {"$filter": 
        {"input": {"$range": [0, {"$size": "$dates"}]},
          "cond": 
          {"$and": 
            [{"$gte": 
                [{"$arrayElemAt": ["$dates", "$$this"]},
                  ISODate("2010-01-01T00:00:00Z")]},
              {"$lte": 
                [{"$arrayElemAt": ["$dates", "$$this"]},
                  ISODate("2020-01-01T00:00:00Z")]}]}}}}},
  {"$set": 
    {"dates": 
      {"$map": 
        {"input": "$indexes",
          "in": {"$arrayElemAt": ["$dates", "$$this"]}}}}},
  {"$set": 
    {"values": 
      {"$map": 
        {"input": "$indexes",
          "in": {"$arrayElemAt": ["$values", "$$this"]}}}}},
  {"$unset": ["indexes"]}])