【问题标题】:How get and use list of fields' name in MongoDB?如何在 MongoDB 中获取和使用字段名称列表?
【发布时间】:2020-08-27 19:14:24
【问题描述】:

我在 MongoDB 中存储每个日期的价格变化数据如下:

{ "_id" : "A1",
  "Price" : 
     {
         "2020-08-25": {"P" : [1200, 1300, 1250]},
         "2020-08-26": {"P" : [1310, 1400, 1200]},
         "2020-08-27": {"P" : [1500, 1300, 1300]},
         ...
     }
 
 },
 { "_id" : "A2",
   "Price" :
     {
          "2020-08-25": {"P" : [1200, 1300, 1250]},
         "2020-08-26": {"P" : [1310, 1400, 1200]},
         "2020-08-27": {"P" : [1500, 1300, 1300]},
         ...
     }
 }

现在,我想获得所有日期的最高价格。如果不在查询中写入每个日期字段,我怎么能做到这一点?我的意思是,对于像“2020-08-25”这样的特定日期,有人可以使用 $group 和 $max 来获得该日期的最大价格值。但是,如何编写查询以获取所有日期中的最大价格值?
谢谢

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    要获取集合中所有日期的最高价格,您需要运行一个聚合操作,首先获取每个文档的最大值,这可以使用 $max$map 运算符创建价格数组来实现可以很容易地推断出最大值。

    要获取数组值,您首先需要将Price 文档转换为日期键/值对数组和使用$objectToArray 的价格

    db.getCollection('collection').aggregate([
        { '$set': {
           'maxPricePerDocument':  {
               '$max': {
                   '$map': {
                       'input': { '$objectToArray': '$Price' },
                       'in': { '$max': '$$this.v.P' }
                   }
               }
           }
        } },
        { '$group': {
            '_id': 0,
            'maxPriceForEntireCollection': { '$max': '$maxPricePerDocument' }
        } }
    ])
    

    【讨论】:

    • 非常感谢@chridam 提供的解决方案。我只是想知道 $objectToArray 的性能。我有数百万条数据记录。剂量 $objectToArray 是否足够快?或者更好的方法是改变我的数据存储方法?例如,一个解决方案是将每个价格存储为 [{"date": "2020-08-25", "p":1200}, {"date": "2020-08-25", "p":1300 },{“日期”:“2020-08-25”,“p”:1250},{“日期”:“2020-08-26”,“p”:1310},{“日期”:“2020- 08-26", "p":1400}, ...]。这样数据量变大了,但是不知道不同查询的性能是好是坏?
    • @AsefPourmasoomi 实际上并没有对特定运算符的性能进行基准测试,但我确信以后一种方式存储数据要好得多,即[{"date": "2020-08-25", "p":1200}, {"date": "2020-08-25", "p":1300}, {"date": "2020-08-25", "p":1250}, {"date": "2020-08-26", "p":1310}, {"date": "2020-08-26", "p":1400}, ...],因为这样你可以只需执行{ maxPrice: { $max: { '$Price.p' } } } 即可,无需先将文档转换为数组,这样可以大大提高性能。
    • Tnx,对于这个查询,性能可能会更好。但是,假设您想查询特定日期。例如,您想对“2020-08-26”的价格进行一些处理。第一种方法可能会更好。因为您可以使用 price["2020-08-26"] 直接访问数据。另一方面,我不确定是否可以在数组的键上定义索引(在第二种方法中,日期字段)。因此,在第二种访问特定日期数据的方法中,我们应该在未索引的字段上使用 $match 添加 where 条件。因此,对于这个查询,第一种方法可能会更好。
    • @AsefPourmasoomi 当然你可以索引一个数组。他们称之为multi-key index 还有其他问题,例如数组可以包含具有相同日期的项目等,但它超出了范围。我很好奇 Chris 的 $map-$max 是否比 Gibbs 的 $group-$max 更好。如果您可以比较两个查询的性能,那就太好了。
    • 非常感谢亚历克斯。我想我应该测试他们两个,我会分享结果。非常感谢。
    【解决方案2】:

    更新:

    浏览收藏

    db.collection.aggregate([
      {
        $project: {
          "prices": {
            "$objectToArray": "$Price"
          }
        }
      },
      {
        $group: {
          "_id": null,
          P: {
            $addToSet: {
              $max: "$prices.v.P"
            }
          }
        }
      },
      {
        $project: {
          "maxPrice": {
            $max: {
              $first: "$P"
            }
          }
        }
      }
    ])
    

    play


    具体日期: playground

    db.collection.aggregate([
      {
        $project: {
          "prices": {//reshape it to perform object wise operations - mainly converting to array
            "$objectToArray": "$Price"
          }
        }
      },
      {//getting one by one entries
        "$unwind": "$prices"
      },
      {
        $group: {//grouping by date and getting the max from local entry
          "_id": "$prices.k",
          "values": {
            $max: "$prices.v.P"
          }
        }
      },
      {
        $project: {
          "date": "$_id",
          "maxPrice": {//getting the max across multiple entries
            $max: "$values"
          },
          "_id": 0
        }
      }
    ])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-03
      • 2022-01-03
      • 1970-01-01
      • 2021-04-02
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多