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

4
我有以下文档,每个文档都包含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")
    ]
  }
]

我想查询我的文档,以便获取在日期“2010-01-01”和日期“2020-01-01”之间(包括这两个日期)的“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可能非常大。

任何帮助都将不胜感激!

1个回答

4

查询

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

*我们可以使用1个reduce完成所有操作,但会嵌套且代码更为复杂,另外$concatArrays速度较慢,将数组缩减为数组也不是一个好主意。下面的方法更简单,即使对于非常大的数组也能正常工作。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接