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)));
            
        }

 

至此結束,寫完覺得還是使用自己不知道的東西有成就感,再接再厲


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM