[英]MongoDB update/insert document and Increment the matched array element
我将Node.js和MongoDB与monk.js结合使用,我希望以最小的方式每小时记录一个文档,例如:
最终文件:
{时间:YYYY-MM-DD-HH,日志:[{动作:action1,计数:1},{动作:action2,计数:27},{动作:action3,计数:5}]}
完整的文档应通过增加一个值来创建。
例如,这个小时有人首先访问网页,而action1的增加应创建带有查询的以下文档:
{时间:YYYY-MM-DD-HH,日志:[{action:action1,count:1}]}
在这个小时内,另一个用户访问了另一个网页,文档应被排除在:
{时间:YYYY-MM-DD-HH,日志:[{动作:action1,计数:1},{动作:action2,计数:1}]}
并且访问不同网页时,计数值应该增加。
目前,我为每个动作创建一个文档:
tracking.update({time:moment()。format('YYYY-MM-DD_HH'),action:action,info:info},{$ inc:{count:1}},{upsert:true},函数(呃){}
monk.js / mongodb是否可能?
编辑:谢谢。 您的解决方案看上去干净优雅,但看起来我的服务器无法处理它,或者我要nooby使其正常工作。
我写了一个极端的肮脏的解决方案,以动作名称作为键:
tracking.update({time:time,ts:ts},JSON.parse('{“ $ inc”:{“'+ action +'”:1}}'),{upsert:true},function(err){ });
是的,这是很有可能的,也是一个深思熟虑的问题。 我对该方法所做的唯一修改是将“时间”值计算为一个实际的Date
对象(在MongoDB中非常有用,并且也可以进行操纵),但只需使用基本日期数学将值“四舍五入”即可。 您可以使用“ moment.js”获得相同的结果,但是我发现数学很简单。
此处的另一个主要考虑因素是将数组“推送”操作与可能的“ updsert”文档操作混合在一起可能是一个实际问题,因此最好使用“多个”更新语句来处理此问题,在这种情况下,只需要更改条件任何东西。
最好的方法是使用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
操作可以确保不进行任何更改,除非该操作实际上“插入”了新文档。
由于所有操作均以“批量”方式触发,因此仅在.execute()
调用中与服务器联系。 因此,尽管有多个操作,但是对服务器只有“一个”请求,只有“一个”响应。 它实际上是一个请求。
这样就可以满足所有条件:
为当前不存在的期间创建一个新文档,并将初始数据插入到数组中。
将新项目添加到当前“操作”分类不存在的数组中,并添加初始计数。
执行语句后,增加数组中指定操作的count属性。
总而言之,是有可能的,而且对于存储来说也是个好主意,只要操作分类在一段时间内不会增长得太大(应将500个数组元素用作最大指导)并且更新非常有效且包含在其中每个时间样本一个文档。
该结构也很好,非常适合其他查询以及可能的其他聚合目的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.