根据日期范围关系

时间:2018-03-23 01:54:08

标签: mongodb mongodb-query

情景:

我有一个集合来保存 sessionLogs ,其中包含以下属性:

  • 用户id
  • 设备类型
  • 的startDate
  • 结束日期

我还有 actionLogs 的另一个集合:

  • 用户id
  • 设备类型
  • createdAt
  • 动作

我无法在actionLogs上引用sessionLog,或者在sessionLog记录中的子集合上添加actionLogs ......这是因为应用程序的性质。 (我认为没有必要为当前的问题解释这一点)

问题:

我需要获得具有特定actionLog的sessionLog的 LIST 。 (以及其他过滤器,如日期,用户等......)

如何仅使用查询执行实现结果?

我认为该组应该使用日期(startDate,endDate),userId和deviceType。

示例:

会话日志

  • userId:x | deviceType:ios | startDate:2018-3-21 | endDate 2018-3-22

与该SessionLog相关的操作日志

  • userId:x | deviceType:ios |日期:2018-3-21 |行动:X
  • userId:x | deviceType:ios |日期:2018-3-22 |行动:Y

1 个答案:

答案 0 :(得分:2)

好吧,如果我理解得很好,可以使用$lookup$unwind(可选)阶段来实现。
由于查找已经"合并/加入"我们的收藏集,以便您通过$match$group阶段通过aggregation pipeline阶段和群组查询任何条件:

我们考虑以下集合:

var sessionsLog = [
    {

        'userId': "132",
        'deviceType': "ios",
        'startDate': ISODate('2018-02-23'),
        'endDate': ISODate('2018-02-28')
    },
    {

        'userId': "789",
        'deviceType': "android",
        'startDate': ISODate('2018-02-15'),
        'endDate': ISODate('2018-02-19')
    },
    {

        'userId': "225",
        'deviceType': "ios",
        'startDate': ISODate('2018-03-01'),
        'endDate': ISODate('2018-03-17')
    }
];

var actionsLog = [
    {

        'userId': '225',
        'deviceType': 'ios',
        'createdAt': ISODate('2018-03-03'),
        'action': 'X'
    },
    {

        'userId': '789',
        'deviceType': 'android',
        'createdAt': ISODate('2018-02-16'),
        'action': 'Y'
    },
    {

        'userId': '789',
        'deviceType': 'android',
        'createdAt': ISODate('2018-02-16'),
        'action': 'Z'
    }
];

db.actionLogs.insert(actionsLog); //via mongo shell...
db.sessionLogs.insert(sessionsLog); //via mongo sheell...

第1步:加入馆藏

$lookup运营商派上用场时。在这里,我们将加入userId字段的馆藏,但这取决于你" wire"按字段收集你想要的东西!

db.sessionLogs.aggregate([
    {
        $lookup: {
            from: 'actionLogs',
            foreignField: 'userId',
            localField: 'userId',
            as: 'action_log'
        }
    }  
])

第2步:过滤文档

  

我需要获取具有特定actionLog的sessionLog的LIST。   (以及其他过滤器,如日期,用户等......)

一旦我们加入了集合,就可以使用$match运算符按照特定条件轻松获取/过滤文档。
但在此之前,我认为在$unwind阶段之前添加$match阶段确实使工作变得更容易(但根本不需要),所以它将是:

db.sessionLogs.aggregate([
    {
        $lookup: {
            from: 'actionLogs',
            foreignField: 'userId',
            localField: 'userId',
            as: 'action_log'
        }
    },
    {
        $unwind: '$action_logs'
    }  
])

它返回:

  {
        "_id": ObjectId("5ab463233a856b4829f5e75d"),
        "userId": "789",
        "deviceType": "android",
        "startDate": ISODate("2018-02-15T00:00:00Z"),
        "endDate": ISODate("2018-02-19T00:00:00Z"),
        "action_log": {
            "_id": ObjectId("5ab463363a856b4829f5e760"),
            "userId": "789",
            "deviceType": "android",
            "createdAt": ISODate("2018-02-16T00:00:00Z"),
            "action": "Y"
        }
    },
    {
        "_id": ObjectId("5ab463233a856b4829f5e75d"),
        "userId": "789",
        "deviceType": "android",
        "startDate": ISODate("2018-02-15T00:00:00Z"),
        "endDate": ISODate("2018-02-19T00:00:00Z"),
        "action_log": {
            "_id": ObjectId("5ab463363a856b4829f5e761"),
            "userId": "789",
            "deviceType": "android",
            "createdAt": ISODate("2018-02-16T00:00:00Z"),
            "action": "Z"
        }
    },
    {
        "_id": ObjectId("5ab463233a856b4829f5e75e"),
        "userId": "225",
        "deviceType": "ios",
        "startDate": ISODate("2018-03-01T00:00:00Z"),
        "endDate": ISODate("2018-03-17T00:00:00Z"),
        "action_log": {
            "_id": ObjectId("5ab463363a856b4829f5e75f"),
            "userId": "225",
            "deviceType": "ios",
            "createdAt": ISODate("2018-03-03T00:00:00Z"),
            "action": "X"
        }
    }

现在我们可以过滤这样的文档(其中action等于X):

db.sessionLogs.aggregate([
    {
        $lookup: {
            from: 'actionLogs',
            foreignField: 'userId',
            localField: 'userId',
            as: 'action_log'
        }
    },
    {
        $unwind: '$action_log'
    },
    {
        $match: {'action_log.action': 'X' }
    }

])

以同样的方式,通过为聚合管道添加$group阶段进行分组应该非常简单!

侧面说明:

  
      
  • $lookup$unwind仅适用于mongodb 3.2+
  •   
  • 请注意在$lookup中添加pipeline阶段就像左外连接一样。
  •   
  • 不要将上述示例作为"规则",它只是一个指南,您很可能会根据您的要求进行更改。
  •