MongoDB结合组聚合和strLenBytes

Posted

技术标签:

【中文标题】MongoDB结合组聚合和strLenBytes【英文标题】:MongoDB combining group aggregation and strLenBytes 【发布时间】:2018-03-05 14:25:20 【问题描述】:

我有一个 Mongo 集合,其中包含这样的文档:


    "_id" : ObjectId("5a9d0d44c3a1ce5f14c6940a"),
    "topic_id" : "5a7af30613b79405643e7da1",
    "value" : "VMware Virtual Platform",
    "timestamp" : "2018-03-05 09:26:25.136546",
    "insert_ts" : "2018-03-05 09:26:25.136682",
    "inserted_by" : 1
,

    "_id" : ObjectId("5a9d0d44c3a1ce5f14c69409"),
    "topic_id" : "5a7af30713b79479f82b4b84",
    "value" : "VMware, Inc.",
    "timestamp" : "2018-03-05 09:26:25.118931",
    "insert_ts" : "2018-03-05 09:26:25.119081",
    "inserted_by" : 1
,

    "_id" : ObjectId("5a9d0d44c3a1ce5f14c69408"),
    "topic_id" : "5a7af30713b7946d6d0a8772",
    "value" : "Phoenix Technologies LTD 6.00 09/21/2015",
    "timestamp" : "2018-03-05 09:26:25.101624",
    "insert_ts" : "2018-03-05 09:26:25.101972",
    "inserted_by" : 1

我想从这个集合中获取一些聚合数据。我想知道最早的时间戳、文档数和所有值的总strlen,但按topic_id分组,其中document-id大于x。

mysql 中,我会像这样构建一个 sql:

SELECT 
    MAX(_id) as max_id,
    COUNT(*) as message_count,
    MIN(timestamp) as min_timestamp,
    LENGTH(GROUP_CONCAT(value)) as size
FROM `dev_topic_data_numeric` 
WHERE _id > 22000
GROUP BY topic_id

我如何在 MongoDB 中实现这一点?我已经尝试过构建它,如下所示:

db.getCollection('topic_data_text').aggregate(
[
    
        "$match": 
        
            "_id": "$gte": ObjectId("5a9d0aefc3a1ce5f14c68c81") 
        
    ,
    
        "$group": 
        
            "_id": "$topic_id",
            "max_id": "$max":"$_id",
            "min_timestamp": "$min": "$timestamp",
            "message_count": "$sum": 1,
            /*"size": "$strLenBytes": "$value" */
        
     
]
);

然后我取消注释 $strLenBytes 它崩溃说 strLenBytes 不是组运算符。 API of MongoDB 在这里对我没有帮助。怎么写才能得到strlen?

我的预期结果应该是这样的:


    "_id" : "5a7af30613b79405643e7da1",
    "max_id" : ObjectId("5a9d0d44c3a1ce5f14c6940a"),
    "min_timestamp" : "2018-03-05 09:26:25.136546",
    "message_count" : 1,
    "size" : 23,

我的 MongoDB 版本是 3.4.4。

【问题讨论】:

你能添加预期的输出吗? 你试过"size": "$sum": "$strLenBytes": "$value" 吗? @RahulSharma 完成。 @chridam 我检查了你的建议。结果错误显示“无效的运算符 $strLenBytes” 我得到的最接近的结果是使用 "$push":"$value" ...但这并不是我想要得到的结果。 【参考方案1】:

这是因为$strLenBytes 不是累加器,不像$sum$max$group 阶段累加值,因此在 $group 阶段有效的任何运算符通常都是累加器。

$strLenBytes 以 1-1 的方式将一个值转换为另一个值。这通常是 $project 阶段的运算符。

在聚合中添加 $project 阶段应该会给您所需的结果。请注意,您还需要稍微修改 $group 阶段以传递所需的值:

> db.test.aggregate([
     
         "$match":
         
             "_id": "$gte": ObjectId("5a9d0aefc3a1ce5f14c68c81") 
         
     ,
     
         "$group":
         
             "_id": "topic_id": "$topic_id", value: "$value",
             "max_id": "$max":"$_id",
             "min_timestamp": "$min": "$timestamp",
             "message_count": "$sum": 1
         
     ,
     
         "$project":
         
             "_id": "$_id.topic_id",
             "max_id": "$max_id",
             "min_timestamp": "$min_timestamp",
             "message_count": "$message_count",
             size: "$strLenBytes": "$_id.value" 
         
     
 ])

使用您的示例文档输出:


  "_id": "5a7af30613b79405643e7da1",
  "max_id": ObjectId("5a9d0d44c3a1ce5f14c6940a"),
  "min_timestamp": "2018-03-05 09:26:25.136546",
  "message_count": 1,
  "size": 23


  "_id": "5a7af30713b79479f82b4b84",
  "max_id": ObjectId("5a9d0d44c3a1ce5f14c69409"),
  "min_timestamp": "2018-03-05 09:26:25.118931",
  "message_count": 1,
  "size": 12


  "_id": "5a7af30713b7946d6d0a8772",
  "max_id": ObjectId("5a9d0d44c3a1ce5f14c69408"),
  "min_timestamp": "2018-03-05 09:26:25.101624",
  "message_count": 1,
  "size": 40

【讨论】:

谢谢。这解决了我的问题,也帮助我更多地理解了项目阶段。在我看来,该文档缺乏对其用途和如何使用它的更深入的解释。【参考方案2】:

在测试了@kevin-adistambha 的答案并进行了一些进一步的实验之后,我找到了另一种方法来实现我想要的结果——也许它有更好的性能——但这需要更多的测试来确定。

db.getCollection('topic_data_text').aggregate(
[
    
        "$match": 
        
            "_id":  "$gt": ObjectId("5a9f9d8bd5de3ac75f8cc269") 
        
    ,
    
        "$group": 
        
            "_id": "$topic_id",
            "max_id": "$max":"$_id",
            "min_timestamp": "$min": "$timestamp",
            "message_count": "$sum": 1,
            "size": "$sum": "$strLenBytes": "$value"
        
    
]
);

【讨论】:

聚合管道还针对某些阶段序列进行优化:docs.mongodb.com/manual/core/aggregation-pipeline-optimization

以上是关于MongoDB结合组聚合和strLenBytes的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB,如何将查找和排序与聚合中的 $cond 结合起来?

MongoDB聚合组和计数字符串

使用 ProjectionDefinition 和 c# 驱动程序的 Mongodb 组聚合

Mongodb聚合管道如何限制组推送

Mongodb geoNear 和组聚合

使用聚合框架使用 MongoDB 进行组计数