MongoDB 聚合 $group 阶段已从外部创建的值/变量
Posted
技术标签:
【中文标题】MongoDB 聚合 $group 阶段已从外部创建的值/变量【英文标题】:MongoDB aggregation $group stage by already created values / variable from outside 【发布时间】:2021-02-28 15:21:34 【问题描述】:成像我有一个对象数组,在aggregate
查询之前可用:
const groupBy = [
realm: 1,
latest_timestamp: 1318874398, //Date.now() values, usually different to each other
item_id: 1234, //always the same
,
realm: 2,
latest_timestamp: 1312467986, //actually it's $max timestamp field from the collection
item_id: 1234,
,
realm: ..., //there are many of them
latest_timestamp: ...,
item_id: 1234,
,
realm: 10,
latest_timestamp: 1318874398, //but sometimes then can be the same
item_id: 1234,
,
]
并使用以下架构收集 (example set available on MongoPlayground):
realm: Number,
timestamp: Number,
item_id: Number,
field: Number, //any other useless fields in this case
我的问题是,如何通过聚合框架使用已经可用的数据集(来自 groupBy)$group
集合中的值?
什么都试过了。
好的,让我们跳过废话,例如:
for (const element of groupBy)
//array of `find` queries
我当前的工作聚合查询是这样的:
//first stage
$match:
"item": 1234
"realm" [1,2,3,4...,10]
,
$group:
_id:
realm: '$realm',
,
latest_timestamp:
$max: '$timestamp',
,
data:
$push: '$$ROOT',
,
,
,
$unwind: '$data',
,
$addFields:
'data.latest_timestamp':
$cond:
if:
$eq: ['$data.timestamp', '$latest_timestamp'],
,
then: '$latest_timestamp',
else: '$$REMOVE',
,
,
,
,
$replaceRoot:
newRoot: '$data',
,
,
//At last, after this stages I can do useful job
但我发现它有点过时了,而且我已经听说使用[.mapReduce][1]
可以比这个查询更快地解决我的问题。 (但官方文档听起来并不乐观)是真的吗?
就目前而言,在开始处理(对我而言)有用的文档之前,我使用了 4 或 5 个阶段。
最近更新:
我检查了$facet
阶段,我发现它对这种特定情况感到好奇。可能会对我有所帮助。
物有所值:
在必要的阶段后收到文件后,我正在构建一个有代表性的聚类图,你可能也知道as a heatmap
之后,我逐个迭代每个文档(或对象数组)以找到它们正确的 x 和 y 协调到位,应该是:
[
x: x (number, actual $price),
y: y (number, actual $realm),
value: price * quantity,
quantity: sum_of_quantity_on_price_level
]
就目前而言,它是一个带有 for...loop 的旧代码,但在未来,我将使用 $facet
=> $bucket
运算符来完成这种工作。
【问题讨论】:
不确定我是否了解确切的问题。是不是这个查询太慢了,你正在寻找一个性能更好的解决方案? 好吧,在某种程度上,真正的问题不是查询本身的性能,而是我花费了大量时间和资源为集合中的每个$realm
查找$latest
时间戳10M+ 文档。实际上已经找到、存储并准备好服务,但不幸的是,我不知道如何在 聚合 $group
阶段使用它们。所以我想学习,有没有办法使用这些数据并扩展我对 MongoDB 本身的体验。因为我知道如何为$match
阶段“导入”变量,但不知道$group
啊,我明白了,您想使用已经存储在变量中的数据作为查询的起点,对吗?如果是这样,那么这取决于您拥有多少组以及您尝试对它们做什么。如果您想将处理拆分为两个并行管道(因此每个管道从同一点开始),您确实可以使用$facet
。
@Avius,谢谢,我也发现它很有用。如果您以前使用过它,可以为我描述一下,如果我有大约 100 个左右的组,它们完全相同的查询,它“可以”使用吗?
那么,您想对这些组做什么?您能否更新您的问题,以便我们可以看到最终结果应该是什么样子?或许也可以添加//At last, after this stages I can do useful job
之后的代码。
【参考方案1】:
因此,我以另一种但相关的方式找到了我的问题的答案。
我正在考虑使用 $facet
运算符,老实说,它仍然是一个选项,但使用它,如下所示是一种不好的做法。
//building $facet query before aggregation
const ObjectQuery =
for (const realm of realms)
Object.assign(ObjectQuery, `$realm.name` : [ ... ]
//mongoose query here
aggregation([
$facet: ObjectQuery
,
...
])
所以,我选择了$project
阶段和$switch
运算符来过滤结果,例如$groups。
另外,使用MapReduce
也可以解决这个问题,但是出于某种原因,Mongo 官方文档recommends to avoid using it,并选择了聚合:$group 和 $merge 运算符。
【讨论】:
以上是关于MongoDB 聚合 $group 阶段已从外部创建的值/变量的主要内容,如果未能解决你的问题,请参考以下文章
MongoDB 聚合比较:group()、$group 和 MapReduce