MongoDB 聚合分组取第一条的案例及实现

栏目: 数据库 · 发布时间: 5年前

内容简介:关键字:MongoDB; aggregate;forEach今天开发同学向我们提了一个紧急的需求,从集合mt_resources_access_log中,根据字段refererDomain分组,取分组中最近一笔插入的数据,然后将这些符合条件的数据导入到集合mt_resources_access_log_new中。接到这个需求,还是有些心虚的,原因有二,一是,业务需要,时间紧;二是,实现这个功能MongoDB聚合感觉有些复杂,聚合要走好多步。

关键字:MongoDB; aggregate;forEach

今天开发同学向我们提了一个紧急的需求,从集合mt_resources_access_log中,根据字段refererDomain分组,取分组中最近一笔插入的数据,然后将这些符合条件的数据导入到集合mt_resources_access_log_new中。

接到这个需求,还是有些心虚的,原因有二,一是,业务需要,时间紧;二是,实现这个功能 MongoDB 聚合感觉有些复杂,聚合要走好多步。

数据记录格式如下:

记录1

{
    "_id" : ObjectId("5c1e23eaa66bf62c0c390afb"),
    "_class" : "C1",
    "resourceUrl" : "/static/js/p.js",
    "refererDomain" : "1234",
    "resourceType" : "static_resource",
    "ip" : "17.17.13.13",
    "createTime" : ISODate("2018-12-22T19:45:46.015+08:00"),
    "disabled" : 0
}

记录2

{
    "_id" : ObjectId("5c1e23eaa66bf62c0c390afb"),
    "_class" : "C1",
    "resourceUrl" : "/static/js/p.js",
    "refererDomain" : "1234",
    "resourceType" : "Dome_resource",
    "ip" : "17.17.13.14",
    "createTime" : ISODate("2018-12-21T19:45:46.015+08:00"),
    "disabled" : 0
}

记录3

{
    "_id" : ObjectId("5c1e23eaa66bf62c0c390afb"),
    "_class" : "C2",
    "resourceUrl" : "/static/js/p.js",
    "refererDomain" : "1235",
    "resourceType" : "static_resource",
    "ip" : "17.17.13.13",
    "createTime" : ISODate("2018-12-20T19:45:46.015+08:00"),
    "disabled" : 0
}


记录4

{
    "_id" : ObjectId("5c1e23eaa66bf62c0c390afb"),
    "_class" : "C2",
    "resourceUrl" : "/static/js/p.js",
    "refererDomain" : "1235",
    "resourceType" : "Dome_resource",
    "ip" : "17.17.13.13",
    "createTime" : ISODate("2018-12-20T19:45:46.015+08:00"),
    "disabled" : 0
}
 

以上是我们的4条记录,类似的记录文档有1500W。

因为情况特殊,业务发版需要这些数据。催的比较急,而 通过 聚合 框架aggregate,短时间有没有思路, 所以,当时就想着尝试采用其他方案。

最后,问题处理方案如下。

Step 1  通过聚合框架 根据条件要求先分组,并将新生成的数据输出到集合mt_resources_access_log20190122 中(共产生95笔数据);

实现代码如下:

db.log_resources_access_collect.aggregate(
                     [
                      
                       { $group: { _id: "$refererDomain" } },
                       { $out : "mt_resources_access_log20190122" }
                     ]
  
                   )

Step 2  通过2次 forEach操作,循环处理 mt_resources_access_log20190122和mt_resources_access_log的数据。

代码解释,处理的逻辑为,循环逐笔取出mt_resources_access_log20190122的数据(共95笔),每笔逐行加工处理,处理的逻辑主要是  根据自己的_id字段数据(此字段来自mt_resources_access_log聚合前的refererDomain字段), 去和 mt_resources_access_log的字段 refererDomain比对,查询出符合此条件的数据,并且是按_id 倒序,仅取一笔,最后将Join刷选后的数据Insert到集合mt_resources_access_log_new。

新集合也是95笔数据。

大家不用担心性能,查询语句在1S内实现了结果查询。

db.mt_resources_access_log20190122.find({}).forEach(
    function(x) {
        db.mt_resources_access_log.find({ "refererDomain": x._id }).sort({ _id: -1 }).limit(1).forEach(
            function(y) {
                db.mt_resources_access_log_new.insert(y)
            }
        )
    }
)

Step 3 查询验证新产生的集合mt_resources_access_log_new,结果符合业务要求。

刷选前集合mt_resources_access_log的数据量为1500多W。

刷选后产生新的集合mt_resources_access_log_new 数据量为95笔。

注意:根据时间 排序 的要求,因为部分文档没有createTime字段类型,且 createTime字段上没有创建索引,所以未了符合按时间排序我们采用了sort({_id:1})的变通方法,因为_id 还有时间的意义。下面的内容为MongoDB对应_id 的相关知识。

MongoDB 聚合分组取第一条的案例及实现

最重要的是前4个字节包含着标准的Unix时间戳。后面3个字节是机器ID,紧接着是2个字节的进程ID。最后3个字节存储的是进程本地计数器。计数器可以保证同一个进程和同一时刻内不会重复。

本文版权归作者所有,未经作者同意不得转载 , 谢谢配合!!!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Visual Thinking

Visual Thinking

Colin Ware / Morgan Kaufmann / 2008-4-18 / USD 49.95

Increasingly, designers need to present information in ways that aid their audiences thinking process. Fortunately, results from the relatively new science of human visual perception provide valuable ......一起来看看 《Visual Thinking》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具