MongoDB 聚合 - $project 和 $cond

标签 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 的长度。

到目前为止,我已经能够编写一个聚合管道,将日志按 $session_id 分组。并提供两个 $events 的数组与 session 相关联。我的想法是接下来我会 $project使用 $cond 为最终结果添加开始和结束时间戳检查event_type每个 $event在数组中,它会告诉我它是否是 beginend事件。我已将到目前为止的内容粘贴在下面:

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/

相关文章:

database - 改变mongodb在mac中的位置

node.js - MongoDB 使用聚合 $lookup 或 Node.js 中的 populate 连接两个集合

mongodb - 如何在使用 MongoDB 聚合框架展开数组后投影数组索引

node.js - 如何使用 Mongoose 和 NodeJS 在 MongoDB 中保存嵌套数组

引用关系的 Mongoid 标准

javascript - 在哪里可以找到 MongoDB 触发的事件列表?

python - 用于简单 python 应用程序的传统 SQL 与 MongoDB/CouchDB

node.js - mongoDB 中的多个 $group

mongodb - 仅检索 MongoDB 集合中对象数组中的查询元素

javascript - 从数组内部计算每个键的不同值