Mongodb聚合查询$match和$group

Posted

技术标签:

【中文标题】Mongodb聚合查询$match和$group【英文标题】:Mongodb aggregate query $match and $group 【发布时间】:2020-09-22 19:14:33 【问题描述】:

以下是我的 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 天内没有条目的用户列表?

【问题讨论】:

你真的有这样的数据吗 ::timestamp: "Jun 4" 表示它是一个字符串还是 timestamp 的数据类型是 date 由于您的timestamp 是字符串格式,您需要使用$dateFromString 运算符,如果您查看文档,只有有限的日期字符串,可以转换。因此,我建议您将字段更新为适当的可转换值。 @whoami ,你说得对。它是数据类型datetimestamp。为了解释清楚,我把它写成一个字符串。但我想我在这样做的时候把别人弄糊涂了。我的错。 嘿@ngShravil.py,感谢您的解决方案帮助。 【参考方案1】:

注意几点:

    请考虑我的评论。

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

    您的$group 不正确。它需要_id 字段,否则会抛出以下错误:

The field '_name' must be an accumulator object.
    我认为,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

【讨论】:

嘿@ngShravil.py,正如我上面提到的,时间戳字段实际上是数据类型date,为了便于解释,我将其显示为字符串。我的错。你的解决方案奏效了。然而,我还有另一个问题。如果有第三个字段怎么办。 status。我只需要选择status: true 所在的行。我通过在$group 之前添加另一个$match 来实现它。有用。但这是正确的方式吗? 是的,没关系。如果这有帮助,那么您可以投票并接受它作为答案。谢谢。

以上是关于Mongodb聚合查询$match和$group的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB $geoNear 聚合管道(使用查询选项和使用 $match 管道操作)给出不同的结果

MongoDB——聚合管道之$match和$count操作

Mongodb聚合$lookup $project和$match不起作用[重复]

Mongodb聚合$lookup $project和$match不起作用[重复]

Mongodb 聚合管道优化 - $match 的 2 阶段

日期和时间过滤器在 find() 操作中工作正常,但 $match 与 mongodb 中的聚合出现问题