我们需要根据“类型”字段跟踪帐户集合中记录的记录计数。因此,我们想知道TYPE1中有多少个帐户,TYPE2中有多少个帐户等...此外,我们需要知道每个帐户中“金额”字段的总数。
聚合查询对我们来说不够快(这些计数需要在UI中实时更新,我们将拥有数百万条记录,需要花费很多秒才能运行的聚合查询不会切割它,所以我正在寻找一个单独的总计集合,其中一个对象跟踪每种类型的计数器。
当我们更改'type'字段的值(即将帐户从一种类型移动到另一种类型)时,我们需要调整计数和'值'总计(减少原始类型的计数器,增加计数器新型)。然后,我们可以使用带有$ incr()的更新命令来调整存储类型计数和值总和的总计记录中的字段。 (这确实意味着我们为每个'类型'更新都有两个数据库写入,但我没有看到解决方法,除非有人有建议)。
对于单个记录调整,这非常简单 - 我们可以在数据访问层中捕获类型更改,并在总计跟踪对象中进行二次更新。
问题是如何跟踪'金额'总计。对于单个记录调整,这不是问题。但对于批量操作(db.collection.update()可能影响数千条记录),我们需要获取每个调整记录的“金额”字段的总和。
到目前为止,我还未能轻易找到让Mongo获取所需信息的方法。
我制定了一个策略,包括在Account对象中添加一个标记的历史数组,其中包含唯一的“changeId”和文档记录在更改时的“金额”,然后针对该策略运行聚合changeId的历史记录获得总数。然后可选择删除历史记录(或在定期清理过程中执行此操作)。
例如,如果我进行了批量更改,我会生成一个唯一的ID(以下为'aaaaaaa'),然后为历史记录执行数组插入,作为调整'type'的批量更新的一部分:
{
"amount": 123,
"type": "TYPE1",
"history": [
{
"changeId": "aaaaaaaaaa",
"amount": 123,
"oldType": "TYPE2",
"newType": "TYPE1"
}
]
}
然后我可以做一个聚合,它给出了刚刚运行的changeId的'amount'的总和。
我认为这会奏效,但它很笨拙 - 有更好的方法吗?
答案 0 :(得分:1)
我的第一直觉是将更改日志存储在单独的集合中,但我没有在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
}
]
}
原因是由于聚合收集过程的时间安排。使用您的原始结构,它必须从帐户本身获取新的金额。但是,如果帐户在聚合收集过程运行之前再次更改,该怎么办比如,交易如下:
Type1 2000
Changes to Type2 3000
Changes to Type1 1000
使用以下结构,您的聚合过程必须忽略类型2更改,因为它会自行取消。
{
"amount": 1000
"type": Type1
"history" [
{
"changeID": "aaaaaa",
"amount": 2000
"oldtype": Type1
"newtype": Type2
},
{
"changeID": "bbbbbb",
"amount": 3000
"oldtype": Type2
"newtype": Type1
}
]
}
我要做以下事情。聚合过程将查找历史记录中的所有Type1记录并执行聚合。因此对于Type1,它将计数1和-1,计数没有差别,-2000和1000将Type1金额减1.Indio2聚合将取消。
{
"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
}
]
}
无论您选择做什么,您都需要确定哪些历史记录已经处理过。您可以删除历史文档一次,标记它们,或将它们移动到审计集合中。