zoukankan      html  css  js  c++  java
  • MongoDB实现数组中重复数据删除

      这个功能真的是写死我了,对于MongoDB一点都不熟悉,本来想使用spring与MongoDB的融合mongoDBTemplate,发现压根不是web项目,懒得配置那些配置文件,就使用最原始的数据库操作,事实证明,是真的很费劲,根本不知道那些操作嘛意思。庆幸的是,姐姐写出来了。

    需求

    现有MongoDB数据库,数据格式如下

      

      data是一数组,查询每条记录中data中存在的重复数据,并删除重复,保留第一条记录

    思路

       根据字段 r ,以及 data 中的 t ,查出重复的数据,再根据重复数据查出完整记录,然后删除重复

    ps : 思路是有的,执行是困难的

    代码

    1. 连接MongoDB数据库,一般可以配置到spring中,我这里使用原始的连接

      

    @SuppressWarnings({"unchecked", "rawtypes" })
        public static void main(String args[]){
            logger.info(String.format("------------------开始处理重复数据,开始时间%s----------------------", new Date()));
            // 当年年初
            Date date = new Date();
            date = DateUtils.truncate(date, Calendar.YEAR);
            
            // 连接到 mongodb 服务,官方文档和源代码均建议使用MongoClient类,而且,在不久的将来,会废弃Mongo类
            MongoClient mongoClient = new MongoClient( "127.0.0.1" , 27017 );
            
            // 连接数据库,你需要指定数据库名称,如果指定的数据库不存在,mongo会自动创建数据库(未测试是否创建,网查可以创建)
            MongoDatabase database = mongoClient.getDatabase("test");
            
            //连接到collection
            MongoCollection coll = database.getCollection("test_data");
            
            List<Document> list = new ArrayList<Document>();
            //固定时间区间,从年初到现在
            Document matchDoc = new Document("t",new Document("$gte", date).append("$lte", new Date()));
            
            // 过滤  $match:用于过滤数据,只输出符合条件的文档                    
            Document match = new Document("$match",matchDoc);
            //$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值
            //拆开data数组
            Document unwind = new Document("$unwind","$data");
            
            // 依据字段 r 与 data中的 t 进行分组,并计算条数
            Document groupD = new Document("_id",new Document("r","$r").append("t", "$data.t"))
                             .append("count", new Document("$sum", 1));
            Document group = new Document("$group", groupD);
            
            // $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
            // 重新定义输出的字段
            Document project = new Document("$project",new Document("r","$_id.r").append("t", "$_id.t").append("num", "$count"));
            
            // 查询条数大于1的数据
            Document match2 = new Document("$match",new Document("num",new Document("$gt",1)));
            
            list.add(match);
            list.add(unwind);
            list.add(group);
            list.add(project);
            list.add(match2);
            
            //Mongodb规定了aggregate管道聚合的返回数据不能超过16M,超过16M就会报异常错误,需要设置allowDiskUse:true,即允许使用磁盘缓存
            AggregateIterable<Document> doc = coll.aggregate(list,Document.class).allowDiskUse(true);
            
            //也可以使用for循环
            doc.forEach(new Block<Document>() {
    
                @Override
                public void apply(Document t) {
                    // TODO Auto-generated method stub
                    logger.info(String.format("重复数据,详情:%s", t));
                    //处理重复数据
                    handleSingleDocument(coll,t);
                    logger.info("---------------------分割线-----------------");
                }
                
            });
            
            // 一定要记得关闭连接
            mongoClient.close();
            mongoClient = null;
            logger.info(String.format("------------------处理重复数据结束,结束时间%s----------------------", new Date()));
        }

      

    handleSingleDocument
    @SuppressWarnings({ "unchecked", "rawtypes" })
        private static void handleSingleDocument(MongoCollection coll,Document t){
            
            //根据重复的条件 r 与 data.t 查询具体的重复数据
            Document unwind = new Document("$unwind","$data");
            Document match = new Document("$match",new Document("r",t.getInteger("r"))
                                                  .append("data.t",t.getDate("t")));
            
            List<Document> list = new ArrayList<Document>();
            list.add(unwind);
            list.add(match);
            AggregateIterable<Document> doc = coll.aggregate(list,Document.class).allowDiskUse(true);
            
            int i = 0;
            for(Document dd :doc){
                //用了最笨的方法,过滤到第一条数据
                if(i==0){
                    i++;
                    continue;
                }
                logger.info(String.format("删除数据:%s", dd));
                Document ment = (Document) dd.get("data");
                
                Document subMatch = new Document("r",t.getInteger("r"))
                                    .append("t", DateUtils.truncate(t.getDate("t"), Calendar.DAY_OF_MONTH));
                
                // updateOne方法,第一个参数是查询符合条件数据,第二个参数是需要做的操作
                // $pull修饰符会删除掉数组中符合条件的元素
                coll.updateOne(subMatch, new Document("$pull",new Document("data",ment)));
                
            }

    至此结束,写完觉得还是使用自己不知道的东西有成就感,再接再厉

  • 相关阅读:
    ASP.NET 服务器控件属性
    SQL Server CE和.NET Compact Framework概述
    用户控件在父页面上事件处理
    jquery怎么实现点击一个元素更换背景图片,连续点击永远在2张图片之间更换
    javascript函数大全
    在代码运行时或者在禁用“只要一个进程中断,就中断所有进程”选项时,不允许进行更改。
    jquery的html,text,val
    饥饿会让人更聪明
    用jquery解析JSON数据的方法
    AOP与OOP
  • 原文地址:https://www.cnblogs.com/Cassie-wang/p/9583794.html
Copyright © 2011-2022 走看看