我们需要根据"类型"字段跟踪帐户集合中记录的记录计数.因此,我们想知道TYPE1中有多少个帐户,TYPE2中有多少个帐户等...此外,我们需要知道每个帐户中"金额"字段的总数.
聚合查询对我们来说不够快(这些计数需要在UI中实时更新,我们将拥有数百万条记录,需要花费很多秒才能运行的聚合查询不会削减它),所以我正在寻找一个单独的总计集合,其中一个对象可以跟踪每种类型的计数器.
当我们更改'type'字段的值(即将帐户从一种类型移动到另一种类型)时,我们需要调整计数和'value'总计(减少原始类型的计数器,增加新类型的计数器) ).然后,我们可以使用带有$ incr()的更新命令来调整存储类型计数和值总和的总计记录中的字段.(这确实意味着我们为每个'类型'更新都有两个数据库写入,但我没有看到解决方法,除非有人有建议).
对于单个记录调整,这非常简单 - 我们可以捕获数据访问层中的类型更改,并在总计跟踪对象中进行二次更新.
问题是如何跟踪'金额'总计.对于单个记录调整,这不是问题.但对于批量操作(db.collection.update()可能影响数千条记录),我们需要获取每个调整记录的"金额"字段的总和.
到目前为止,我还没有能够轻松找到让Mongo获取我需要的信息的方法.
我有一个策略,包括在Account对象中添加一个标记的历史数组,其中包含唯一的"changeId"和文档记录在更改时的"金额",然后针对该历史记录运行聚合changeId得到总数.然后可选择删除历史记录(或在定期清理过程中执行此操作).
例如,如果我进行了批量更改,我会生成一个唯一的ID(以下为'aaaaaaa'),然后在调整'type'的批量更新中为历史记录执行数组插入:
{
"amount": 123,
"type": "TYPE1",
"history": [
{
"changeId": "aaaaaaaaaa",
"amount": 123,
"oldType": "TYPE2",
"newType": "TYPE1"
}
]
}
Run Code Online (Sandbox Code Playgroud)
然后我可以做一个聚合,它给我刚刚运行的changeId的'amount'的总和.
我认为这会奏效,但它很笨拙 - 有更好的方法吗?
我的第一直觉是将更改日志存储在单独的集合中,但我在 MongoDB 批量集合文档中没有看到这样做的方法。我同意维护总量的工作需要在一个单独的过程中进行。您在帐户集合中创建历史记录数组的想法可以实现。我不知道你的应用程序,但我会稍微改变结构以避免计时漏洞。我会创建一个汇总过程可以在对帐户知之甚少的情况下应用的更改的收报机磁带。
{
"amount": active amount,
"type": active type,
"history" [
{
"changeId": "aaaaaaaa",
"NewType": 1
"amount": new amount
},
{
"changeId": "aaaaaaaa",
"OldType": -1
"amount": old amount as a negative value
}
]
}
Run Code Online (Sandbox Code Playgroud)
原因是聚合收集过程的时间安排。使用您的原始结构,它必须从帐户本身获取新金额。但是,如果在聚合收集过程运行之前帐户再次发生更改怎么办?比如说,交易如下:
Type1 2000
Changes to Type2 3000
Changes to Type1 1000
Run Code Online (Sandbox Code Playgroud)
使用以下结构,您的聚合流程必须设法忽略类型 2 更改,因为它会自行取消。
{
"amount": 1000
"type": Type1
"history" [
{
"changeID": "aaaaaa",
"amount": 2000
"oldtype": Type1
"newtype": Type2
},
{
"changeID": "bbbbbb",
"amount": 3000
"oldtype": Type2
"newtype": Type1
}
]
}
Run Code Online (Sandbox Code Playgroud)
我会做以下事情。聚合过程将查找历史记录中的所有 Type1 记录并执行聚合。因此,对于 Type1,它将对 1 和 -1 求和,以确保计数没有差异;对 -2000 和 1000 求和,将 Type1 金额减少 1000。Type2 合计将抵消。
{
"amount": 1000
"type": Type1
"history" [
{
"changeID": "aaaaaa",
"Type1": -1
"amount": -2000
},
{
"changeID": "aaaaaa",
"Type2": 1
"amount": 3000
},
{
"changeID": "bbbbbb",
"Type2": -1
"amount": -3000
},
{
"changeID": "bbbbbb",
"Type1": 1
"amount": 1000
}
]
}
Run Code Online (Sandbox Code Playgroud)
无论您选择做什么,您都需要确定哪些历史记录已被处理。您可以在处理后删除历史文档、标记它们或将它们移至审核集合。