Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb 加快大型集合上的聚合_Mongodb_Mongodb Query_Aggregation Framework - Fatal编程技术网

Mongodb 加快大型集合上的聚合

Mongodb 加快大型集合上的聚合,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我目前有一个数据库,包含大约27万个文档。它们看起来像这样: [{ 'location': 'Berlin', 'product': 4531, 'createdAt': ISODate(...), 'value': 3523, 'minOffer': 3215, 'quantity': 7812 },{ 'location': 'London', 'product': 1231, 'createdAt': ISODate(

我目前有一个数据库,包含大约27万个文档。它们看起来像这样:

[{
    'location': 'Berlin',
    'product': 4531,
    'createdAt': ISODate(...),
    'value': 3523,
    'minOffer': 3215,
    'quantity': 7812
},{
    'location': 'London',
    'product': 1231,
    'createdAt': ISODate(...),
    'value': 53523,
    'minOffer': 44215,
    'quantity': 2812
}]
该数据库目前拥有一个多月的数据,拥有约170个地点(在欧盟和美国),约8000种产品。这些文档表示时间步,因此每个位置的每个产品每天大约有12-16条条目(但最多每小时1条)。
我的目标是检索过去7天内给定位置的产品的所有时间步。对于单个位置,此查询使用索引
{product:1,location:1,createdAt:-1}
以合理的速度运行(150ms)

然而,我也需要这些时间步长,不仅仅是针对单个位置,而是针对整个区域(大约85个位置)。我目前正在使用此聚合进行此操作,它将每小时的所有条目分组,并平均所需的值:

this.db.collection(“…”).aggregate([
{$match:{{location:{$in:[85个位置的数组]},product:productId,createdAt:{$gte:newdate(Date.now()-sevenDaysAgo)}{
$group:{
_身份证:{
$toDate:{
$concat:[
{$toString:{$year:'$createdAt'}},
'-',
{$toString:{$month:'$createdAt'}},
'-',
{$toString:{$dayOfMonth:'$createdAt'}},
' ',
{$toString:{$hour:'$createdAt'}},
':00'
]
}
},
值:{$avg:'$value'},
minOffer:{$avg:'$minOffer'},
数量:{$avg:'$quantity'}
}
}
]).sort({u id:1}).toArray()
但是,即使使用索引
{product:1,createdAt:-1,location:1}
(~40秒),这也非常慢。有没有办法加快聚合速度,使其最多只需几秒钟?这可能吗,或者我应该考虑使用其他东西吗?

我曾经考虑过将这些聚合保存在另一个数据库中,然后检索并聚合其余的,但是对于网站上第一批用户来说,这真的很尴尬,因为他们不得不等待40秒。

这些想法可以提高查询和性能。所有这些能否共同发挥作用,还需要进行一些试验和测试。另外,请注意,更改数据的存储方式和添加新索引意味着应用程序将发生更改,即捕获数据,并且需要仔细验证对相同数据的其他查询(确保它们不会以错误的方式受到影响)


(A)在文档中存储一天的详细信息:

将一天的数据作为子文档数组存储(嵌入)到同一文档中。每个子文档代表一个小时的条目

发件人:

致:

这意味着每个文档大约有10个条目。为条目添加数据将把数据推送到details数组中,而不是像当前应用程序那样添加文档。如果需要小时信息(时间),也可以将其存储为详细信息子文档的一部分;这将完全取决于您的应用程序需要

这种设计的好处是:

  • 要维护和查询的文档数量将减少(每 每天的产品(约10个文档)
  • 在查询中,组阶段将消失。这将只是一个简单的例子 项目阶段。请注意,
    $project
    支持
    $avg
    $sum
下一阶段将创建当天的总和和平均值(或文档)

注意:文档大小的增加不多,每天存储的详细信息量也不多


(B)按地区查询:

当前多个位置(或区域)与此查询文件服务器的匹配:
{location:{$in:[85个位置的数组]}
。此筛选器显示:
location:location-1,-或-location:location-3,-或-…,location:location-50
。添加一个新字段,
region
,将使用一个匹配值进行筛选

按区域的查询将更改为:

{ 
  $match: { 
      region: regionId, 
      product: productId, 
      createdAt: { $gte: new Date(Date.now() - sevenDaysAgo) } 
  } 
}
将提供
regionId
变量以与区域字段匹配

请注意,“按位置”和“按区域”查询都将受益于上述两个考虑因素,AB


(C)索引注意事项:

当前索引:
{product:1,location:1,createdAt:-1}

考虑到新字段
区域
,需要更新索引。如果区域字段上没有索引,则带有区域的查询将无法受益。需要第二个索引;适合查询的复合索引。使用区域字段创建索引意味着写操作的额外开销。此外,还需要考虑内存和存储问题

注意事项:

添加索引后,如果查询使用各自的索引,则需要使用
explain
验证查询(“按位置”和“按区域”)。这需要一些测试;反复试验的过程

再次,添加新的数据,以不同的格式存储数据,添加新的索引需要考虑这些:

  • 仔细测试和验证其他现有查询是否正常运行
  • 数据捕获需求的变化
  • 测试新查询并验证新设计是否按预期执行

老实说,您的聚合已经尽可能地优化了,特别是如果您有
{product:1,createdAt:-1,location:1}
作为您所述的索引

我不太清楚您的整个产品是如何构建的,但是我认为最好的解决方案是再收集一个只包含上周“相关”文档的集合

然后,您可以轻松地查询该集合,这在Mongo中也很容易使用。
{
    location: 'London',
    product: 1231,
    createdAt: ISODate(...),
    details: [ { value: 53523, minOffer: 44215, quantity: 2812 }, ... ]
}
{ 
    $project: { value: { $avg: '$value' }, minOffer: { $avg: '$minOffer' }, quantity: { $avg: '$quantity' } }
}
{ 
  $match: { 
      region: regionId, 
      product: productId, 
      createdAt: { $gte: new Date(Date.now() - sevenDaysAgo) } 
  } 
}