我已经在 mongo 数据库中记录了来自信息系统的更改。每次设置或更改一组值时,都会在 mongo 数据库中保存一条记录。
变更集合采用以下形式:
{ "user_id": 1, "timestamp": { "date" : "2010-09-22 09:28:02", "timezone_type" : 3, "timezone" : "Europe/Paris" } }, "changes: { "fieldA": "valueA", "fieldB": "valueB", "fieldC": "valueC" } }
{ "user_id": 1, "timestamp": { "date" : "2010-09-24 19:01:52", "timezone_type" : 3, "timezone" : "Europe/Paris" } }, "changes: { "fieldA": "new_valueA", "fieldB": null, "fieldD": "valueD" } }
{ "user_id": 1, "timestamp": { "date" : "2010-10-01 11:11:02", "timezone_type" : 3, "timezone" : "Europe/Paris" } }, "changes: { "fieldD": "new_valueD" } }
当然,每个用户有数千条具有不同属性的记录,代表数百万条记录。我想要做的是在给定时间查看用户状态。例如,2010 年 9 月 30 日的 user_id 1 将是
fieldA: new_valueA
fieldC: valueC
fieldD: valueD
这意味着我需要将给定用户在给定日期之前的所有更改拼合到一条记录中。我可以直接在 mongo 中这样做吗?
编辑:我使用的是 2.0 版本的 mongodb,因此无法从聚合框架中受益。
编辑:听起来我已经找到了我的问题的答案。
var mapTimeAndChangesByUserId = function() {
var key = this.user_id;
var value = { timestamp: this.timestamp.date, changes: this.changes };
emit(key, value);
}
var reduceMergeChanges = function(user_id, changeset) {
var mergeFunction = function(a, b) { for (var attr in b) a[attr] = b[attr]; };
var result = {};
changeset.forEach(function(e) { mergeFunction(result, e.changes); });
return { timestamp: changeset.pop().timestamp, changes: result };
}
reduce 函数按它们来的顺序合并更改并返回结果。
db.user_change.mapReduce(
mapTimeAndChangesByUserId,
reduceMergeChanges,
{
out: { inline: 1 },
query: { user_id: 1, "timestamp.date": { $lt: "2010-09-30" } },
sort: { "timestamp.date": 1 }
});
'results' : [
"_id": 1,
"value": {
"timestamp": "2010-09-24 19:01:52",
"changes": {
"fieldA": "new_valueA",
"fieldB": null,
"fieldC": "valueC",
"fieldD": "valueD"
}
}
]
这对我来说很好。