這個功能真的是寫死我了,對於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)));
}
至此結束,寫完覺得還是使用自己不知道的東西有成就感,再接再厲
