我正在尝试使用 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 的长度。
到目前为止,我已经能够编写一个聚合管道,将日志按 $session_id
分组。并提供两个 $events
的数组与 session 相关联。我的想法是接下来我会 $project
使用 $cond
为最终结果添加开始和结束时间戳检查event_type
每个 $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" }
我认为我的问题出在 if
我的$cond
,我在这里比较 event_type
的值每个 $event
的字段用一个字符串来查看它是否是我们两个 begin
之一或 end
事件类型。我相信它在这个 $if $or $strcasecompare
的某个地方我哪里有问题...
我曾尝试使用 $literal
比较 event_type
也没有结果。
任何帮助将不胜感激!
最佳答案
对于 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 个与 session 匹配的事件(开始和结束)记录,那么您可以安全地使用 $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 .
关于MongoDB 聚合 - $project 和 $cond,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42850155/