首页 > 解决方案 > Mongodb聚合查询$match和$group

问题描述

以下是我的 mongodb 集合中的一些示例条目:

{ name: "Tom", timestamp: "Jun 4" },
{ name: "Jerry", timestamp: "Jun 4" },
{ name: "Tom", timestamp: "Jun 2" },
{ name: "Tom", timestamp: "May 25" },
{ name: "Jerry", timestamp: "May 21" },
{ name: "Robin", timestamp: "May 19" }

每次用户登录我的应用程序时,我都会为该用户创建一个条目。

问题:我需要找出过去 5 天未登录我的应用的用户列表。也就是5 月 30 日之后不能进入。今天是6 月 4 日

答案: 罗宾

尝试1:

[ 
   { "$match": { "timestamp": { "$lt": FIVE_DAYS_AGO } } }, 
   { "$sort": { "timestamp": 1 } },
   { "$group": { "_name": "$name", "lastSynced": { "$last": "$timestamp" } }
]

给出不正确的结果,因为 NOW 和 FIVE_DAYS_AGO 之间可能存在未被考虑的条目。

尝试2:

[
   { "$sort": { "timestamp": 1 } },
   { "$group": { "_name": "$name", "lastSynced": { "$last": "$timestamp" } }
]

未优化!因为它返回所有不同的用户条目。然后我必须遍历结果并过滤掉时间戳为 FIVE_DAYS_AGO 的条目。

如何构建查询以获取过去 X 天内没有条目的用户列表?

标签: mongodbmongoosemongodb-queryaggregation-frameworkpymongo

解决方案


需要注意的几点:

  1. 请考虑我的评论。

    由于您timestamp是字符串格式,因此您需要使用$dateFromString运算符,如果您查看文档,则只有有限的日期字符串可以转换。因此,我建议您将该字段更新为适当的可兑换价值。

  2. $group的不正确。它需要_id字段,否则将引发以下错误:

The field '_name' must be an accumulator object.
  1. 我认为,年份值是必需的timestamp,我收到了这个错误:
(ConversionFailure) Error parsing date string

考虑到以上几点,如果您的收藏如下所示:

[
  {
    name: "Tom",
    timestamp: "06 04 2020"
  },
  {
    name: "Jerry",
    timestamp: "06 04 2020"
  },
  {
    name: "Tom",
    timestamp: "06 02 2020"
  },
  {
    name: "Tom",
    timestamp: "05 25 2020"
  },
  {
    name: "Jerry",
    timestamp: "05 21 2020"
  },
  {
    name: "Robin",
    timestamp: "05 19 2020"
  }
]

那么下面的 PyMongo 查询会有所帮助:

from datetime import datetime

five_days_ago = datetime(2020, 5, 30)

db.test12.aggregate([
  {
    '$group': {
      '_id': '$name',
      'timestap_list': {
        '$push': {
          '$dateFromString': {
            'dateString': '$timestamp',
            'format': '%m %d %Y'
          }
        }
      }
    }
  },
  {
    '$project': {
      'timestamp': {
        '$allElementsTrue': {
          '$map': {
            'input': '$timestap_list',
            'as': 't',
            'in': {
              '$lte': [
                '$$t',
                five_days_ago
              ]
            }
          }
        }
      }
    }
  },
  {
    '$match': {
      'timestamp': True
    }
  },
  {
    '$project': {
      'timestamp': 0
    }
  }
])

输出:

{
  '_id': 'Robin'
}

MongoPlayGroundLink


推荐阅读