我尝试使用MongoDBs(v.3.2.11)聚合框架来处理一些如下所示的日志文档:
{
"_id" : ObjectId("58b753c6d4421f00216de942"),
"session_id" : "7CB8725A-3994-45B8-9CA2-92FC19406288",
"event_type" : "connect_begin",
"timestamp" : "1488409541.674997",
"user_id" : "f6830aac-60be-44df-9fa7-7aa530d637ce",
"u_at" : ISODate("2017-03-01T23:05:42.077Z"),
"c_at" : ISODate("2017-03-01T23:05:42.077Z")
}
我的收藏包含以上共享session_id
的日志对,begin
事件的一个日志和end
事件的一个日志。最终目标是通过时间戳的差异来计算这些会话的长度。
到目前为止,我已经能够编写一个聚合管道,按$session_id
对日志进行分组,并提供与会话关联的两个$events
的数组。我的想法是接下来我会$project
使用$cond
检查最终结果的开始和结束时间戳,以检查数组中每个event_type
的{{1}},这将告诉我们我,如果是$event
或begin
事件。我已粘贴到目前为止的内容:
end
这会产生以下列表:
db.time_spent_logs.aggregate([
{ $group: {
_id: '$session_id',
events: {
$push: {
event_type: '$event_type',
timestamp: '$timestamp'
}
}
}},
{ $project: {
start: {
$cond: {
if: { $or: [ { $strcasecmp: [ "$events[0].event_type", "trending_begin" ]}, { $strcasecmp: [ "$events[0].event_type", "connect_begin" ]}] },
then: '$events[0].timestamp',
else: '$events[1].timestamp'
}
},
end: {
$cond: {
if: { $or: [ { $strcasecmp: [ "$events[0].event_type", "trending_end" ]}, { $strcasecmp: [ "$events[0].event_type", "connect_end" ]}] },
then: '$events[0].timestamp',
else: '$events[1].timestamp'
}
}
}}
])
我认为我的问题出在我{ "_id" : "4EC4B831-D3C7-49C6-9EC8-301981639ED7" }
的{{1}}中,我将每个if
的{{1}}字段的值与字符串进行比较,看看是否它是我们的两个$cond
或event_type
事件类型之一。我相信这是$event
的某个地方,我有些不对劲......
我尝试使用begin
来比较end
以及没有结果。
非常感谢任何帮助!
答案 0 :(得分:5)
对于MongoDB v 3.2及更高版本,您可以使用$filter而不是像这样手动应用条件:
{
$project: {
start: {
//Filter the events, keep only 'begin' events
$filter: {
input: '$events',
as: 'event',
cond: {$in: ['$$event.event_type', ['trending_begin', 'connect_begin']]}
}
},
end: {
//Same with 'end' events
$filter: {
input: '$events',
as: 'event',
cond: {$in: ['$$event.event_type', ['trending_end', 'connect_end']]}
}
}
}
}

因此产生的'开始'并且'结束'属性将分别是开始和结束事件的数组。 如果你确定数据是一致的,并且你有2个匹配会话的事件(开始和结束)记录,那么你可以安全地使用$arrayElemAt来获取数组的第一个元素:
{
$project: {
start: {
//Take first of the filtered events
$arrayElemAt: [{
$filter: {
input: '$events',
as: 'event',
cond: {$in: ['$$event.event_type', ['trending_begin', 'connect_begin']]}
}
}, 0]
},
end: {
//Take first of the filtered events
$arrayElemAt: [{
$filter: {
input: '$events',
as: 'event',
cond: {$in: ['$$event.event_type', ['trending_end', 'connect_end']]}
}
}, 0]
}
}
}

你已经开始'并且'结束'作为普通物体。 这是whole query。