MongoBD每天显示每个用户的第一个和最后一个事件

时间:2018-10-09 09:58:34

标签: mongodb mongodb-query

每次用户登录或注销时,事件都会保存在mongo中。用户一天可以多次登录和/或注销。

例如,鲍勃(Bob)拥有2次登录和1次注销:

{
  username: ‘bob’,
  type: ‘login’,
  eventDate: ISODate(‘2018-09-21T12:39:50.676Z’)
}

{
  username: ‘bob’,
  type: ‘login’,
  eventDate: ISODate(‘2018-09-21T13:55:50.676Z’)
}

{
  username: ‘bob’,
  type: ‘logout,
  eventDate: ISODate(‘2018-09-21T22:10:50.676Z’)
}

James只有1个登录事件:

{
  username: ‘james’,
  type: ‘login,
  eventDate: ISODate(‘2018-09-21T10:10:50.676Z’)
}

我想执行一个查询,该查询将为每个用户每天检索当天的首次登录和最后的注销(例如,在过去一周)。

结果将是:

[{
  username: ‘bob’,
  firstLogin: ISODate(‘2018-09-21T12:39:50.676Z’),
  lastLogout: ISODate(‘2018-09-21T22:10:50.676Z’)
}

{
  username: ‘james’,
  firstLogin: ISODate(‘2018-09-22T10:19:50.676Z’),
  lastLogout: null,
}]

我认为我必须处理“聚合”问题,但不确定。

2 个答案:

答案 0 :(得分:2)

通过使用两个级别的$group(MongoDB V3.2.18)

我相信用户名是唯一的。

    首先
  1. $sort eventDate
  2. $group通过用户名类型
  3. $project来区分 firstLogin lastLogin
  4. 再次用户名
  5. $group,以获得最终结果。

db.getCollection('test').aggregate([
  {$sort: {'eventDate' : 1}},
  {
    "$group" : {
        _id: {"username" : "$username", "type": "$type"},
        eventDate: {$push: "$eventDate"}
    }
  },
  {
    $project : {
      _id:1,
      eventDate:1,
      firstLogin: {
        $cond: [ { "$eq": ["$_id.type", "login" ]}, { $arrayElemAt: [ "$eventDate", 0 ] }, null]
      },
      lastLogout: {
        $cond: [ { "$eq": ["$_id.type", "logout" ]}, { $arrayElemAt: [ "$eventDate", -1 ] }, null]
      }
    }
  },
  {
    "$group" : {
        _id: "$_id.username",
        firstLogin: {$first: "$firstLogin"},
        lastLogout: {$last: "$lastLogout"}
    }
  }
]);

输出:

/* 1 */
{
    "_id" : "james",
    "firstLogin" : ISODate("2018-09-21T10:10:50.676Z"),
    "lastLogout" : null
}

/* 2 */
{
    "_id" : "bob",
    "firstLogin" : ISODate("2018-09-21T12:39:50.676Z"),
    "lastLogout" : ISODate("2018-09-21T22:10:50.676Z")
}

答案 1 :(得分:1)

您可以通过单个group来实现。

  

同一用户的不同日子也可以工作。

     

type前返回最后一个日期和第一个日期。

     

在MongoDB GUI上进行了测试。

db.getCollection("loginDetail").aggregate([
  {
    $group: {
      _id: {
        username: "$username",
        year: { $year: "$eventDate" },
        month: { $month: "$eventDate" },
        day: { $dayOfMonth: "$eventDate" }
      },
      firstLogin: {
        $min: {
          $cond: [{ $and: [{ $eq: ["$type", "login"] }] }, "$eventDate", null]
        }
      },
      lastLogout: {
        $max: {
          $cond: [{ $and: [{ $eq: ["$type", "logout"] }] }, "$eventDate", null]
        }
      }
    }
  },
  {
      $project: {
          _id: 1,
          username : '$_id.username',
          firstLogin :1,
          lastLogout :1
          }
      }
]);