MongoDB聚合 - $ item with $ cond

时间:2017-03-17 05:51:08

标签: mongodb aggregation-framework

我尝试使用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}},这将告诉我们我,如果是$eventbegin事件。我已粘贴到目前为止的内容:

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}}字段的值与字符串进行比较,看看是否它是我们的两个$condevent_type事件类型之一。我相信这是$event的某个地方,我有些不对劲......

我尝试使用begin来比较end以及没有结果。

非常感谢任何帮助!

1 个答案:

答案 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