我使用Node.js和MongoDB和monk.js,我希望以最小的方式进行日志记录,每小时一个文档,如:
最终文档:
{time:YYYY-MM-DD-HH,log:[{action:action1,count:1},{action:action2,count:27},{action:action3,count:5}]}
应该通过递增一个值来创建完整的文档。
例如,某人此时首先访问网页,并且action1的增加应使用查询创建以下文档:
{time:YYYY-MM-DD-HH,log:[{action:action1,count:1}]}
此时的其他用户访问其他网页,文档应扩展为:
{time:YYYY-MM-DD-HH,log:[{action:action1,count:1},{action:action2,count:1}]}
并且在访问不同的网页时,应增加count中的值。
目前我在每个动作中创建一个doc:
tracking.update({ 时间:时刻()。格式(' YYYY-MM-DD_HH'), 行动:行动, 信息:信息 },{$ inc:{count:1}},{upsert:true},function(err){}
这可以用monk.js / mongodb吗?
修改 谢谢。您的解决方案看起来干净而优雅,但看起来我的服务器无法处理它,或者我没有让它工作。
我写了一个非常脏的解决方案,其中action-name为关键:
tracking.update({time:time,ts:ts},JSON.parse(' {" $ inc": {"' + action +'":1}}'),{upsert:true},function(err){});
答案 0 :(得分:1)
是的,这是非常可能的,也是一个考虑周全的问题。我在这种方法上唯一的变化是计算"时间"值作为一个真正的Date
对象(在MongoDB中非常有用,也可以在操作中使用)但只是简单地“#34; round"基本日期数学的值。你可以使用" moment.js"为了相同的结果,但我发现数学很简单。
这里的另一个主要考虑因素是混合阵列" push"有可能的行动" updsert"文档操作可能是一个真正的问题,因此最好使用" multiple"更新语句,只有你想要的条件才会改变任何东西。
最好的方法是使用MongoDB Bulk Operations。
请考虑您的数据是这样的:
{ "timestamp": 1439381722531, "action": "action1" }
"时间戳"是一个纪元时间戳值,精确到毫秒。所以处理这个看起来像:
// Just adding for the listing, assuming already defined otherwise
var payload = { "timestamp": 1439381722531, "action": "action1" };
// Round to hour
var hour = new Date(
payload.timestamp - ( payload.timestamp % ( 1000 * 60 * 60 ) )
);
// Init transaction
var bulk = db.collection.initializeOrderedBulkOp();
// Try to increment where array element exists in document
bulk.find({
"time": hour,
"log.action": payload.action
}).updateOne({
"$inc": { "log.$.count": 1 }
});
// Try to upsert where document does not exist
bulk.find({ "time": hour }).upsert().updateOne({
"$setOnInsert": {
"log": [{ "action": payload.action, "count": 1 }]
}
});
// Try to "push" where array element does not exist in matched document
bulk.find({
"time": hour,
"log.action": { "$ne": payload.action }
}).updateOne({
"$push": { "log": { "action": payload.action, "count": 1 } }
});
bulk.execute();
因此,如果你仔细研究那里的逻辑,那么你会发现只有"一个"对于文件的任何给定状态是否存在,这些陈述是真实的。从技术上讲,这个声明与" upsert"实际上可以匹配文档,但是使用的$setOnInsert
操作会确保进行无更改,除非该操作实际上是"插入"一份新文件。
由于所有操作都是在" Bulk"中触发的,因此唯一一次联系服务器的时间是.execute()
。所以只有"一个"请求服务器,只有"一个"响应,尽管多次操作。它实际上是一个"一个"请求。
这样就满足了条件:
为当前时段创建一个不存在的新文档,并将初始数据插入到数组中。
将新项目添加到当前" action"分类不存在并添加初始计数。
执行语句时,增加数组中指定操作的count属性。
总而言之,是可能的,并且只要行动分类在一段时间内不会变得太大(500个数组元素应该被用作最大指南)并且更新非常有效并且也是存储的好主意。每个时间样本都包含在一个文档中。
结构也很好,非常适合其他查询和可能的附加聚合目的。