繁体   English   中英

使用聚合管道在MongoDB中聚合时间戳集合

[英]Aggregate a collection of timestamps in MongoDB using the Aggregation Pipeline

我收集了一些时间戳,这些时间戳记录了用户在什么时候执行了哪些操作。 目前,该集合仅包含两个操作startend 每个用户只能有一个end动作,而每个用户可以有多个start动作。

现在,我要生成一个用户列表,其中上一个start操作和end操作之间的时间差(例如)少于一分钟。

我的集合timestamps的简化文档如下所示:

document #1

{
  id: 123,
  user: "user1",
  type: "start",
  date: 2019-09-10
}

document #2

{
  id: 234,
  user: "user1",
  type: "end",
   date: 2019-09-11
}

现在我想要的结果应如下所示:

{
  id: null,
  list: ["user1, user2"]
}

字段list应包含每个用户, startend操作之间的时间差小于一分钟。

我在合并包含startend属性的文档时遇到了麻烦。 我试图将它们组合成如下所示的文档:

{
  id: 345
  user: "user1"
  date_start: 2019-09-10
  date_end: 2019-09-11
}

我不知道从哪里开始聚合管道,以及如何拆分和组合不同类型的时间戳。 此外,我仍然需要添加一个包含两个日期之间差异的字段。

以下查询可以为我们提供预期的输出:

db.collection.aggregate([
    {
        $sort:{
            "date":-1
        }
    },
    {
        $group:{
            "_id":{
                "id":"$id",
                "type":"$type"
            },
            "id":{
                $first:"$id"
            },
            "user":{
                $first:"$user"
            },
            "type":{
                $first:"$type"
            },
            "date":{
                $first:"$date"
            }
        }
    },
    {
        $group:{
            "_id":"$id",
            "user":{
                $first:"$user"
            },
            "info":{
                $push:{
                    "k":"$type",
                    "v":"$date"
                }
            }
        }
    },
    {
        $addFields:{
            "info":{
                $arrayToObject:"$info"
            }
        }
    },
    {
        $match:{
            $expr:{
                $lt:[
                    {
                        $subtract:[
                            {
                                $toDate:"$info.end"
                            },
                            {
                                $toDate:"$info.start"
                            }
                        ]
                    },
                    60000
                ]
            }
        }
    },
    {
        $group:{
            "_id":null,
            "users":{
                $push:"$user"
            }
        }
    },
    {
        $project:{
            "_id":0
        }
    }
]).pretty()

数据集:

{
    "_id" : ObjectId("5d77a117bd4e75c58d598214"),
    "id" : 123,
    "user" : "user1",
    "type" : "start",
    "date" : "2019-09-10T13:01:14.242Z"
}
{
    "_id" : ObjectId("5d77a117bd4e75c58d598215"),
    "id" : 123,
    "user" : "user1",
    "type" : "start",
    "date" : "2019-09-10T13:04:14.242Z"
}
{
    "_id" : ObjectId("5d77a117bd4e75c58d598216"),
    "id" : 123,
    "user" : "user1",
    "type" : "start",
    "date" : "2019-09-10T13:09:02.242Z"
}
{
    "_id" : ObjectId("5d77a117bd4e75c58d598217"),
    "id" : 123,
    "user" : "user1",
    "type" : "end",
    "date" : "2019-09-10T13:09:14.242Z"
}
{
    "_id" : ObjectId("5d77a117bd4e75c58d598218"),
    "id" : 234,
    "user" : "user2",
    "type" : "start",
    "date" : "2019-09-10T13:02:02.242Z"
}
{
    "_id" : ObjectId("5d77a117bd4e75c58d598219"),
    "id" : 234,
    "user" : "user2",
    "type" : "end",
    "date" : "2019-09-10T13:09:14.242Z"
}
{
    "_id" : ObjectId("5d77a117bd4e75c58d59821a"),
    "id" : 345,
    "user" : "user3",
    "type" : "start",
    "date" : "2019-09-10T13:08:55.242Z"
}
{
    "_id" : ObjectId("5d77a117bd4e75c58d59821b"),
    "id" : 345,
    "user" : "user3",
    "type" : "end",
    "date" : "2019-09-10T13:09:14.242Z"
}

输出:

{ "users" : [ "user3", "user1" ] }

查询分析:

  • 第一阶段:按日期降序对文档进行排序
  • 第二阶段:[id, type]分组并为每种类型选择第一个日期,即每种类型的最新日期
  • 第三阶段:仅按id分组,然后将类型和相关日期作为键值对推入数组
  • 阶段IV:将键值对数组转换为对象
  • 阶段V:筛选文档,其结束日期与开始日期之间的差值小于60000毫秒。 (毫秒等于1分钟)
  • 第六阶段:将所有过滤后的名称放入数组

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM