1. 程式人生 > 資料庫 >MONGODB04 - 資料聚合Aggregation進階之lookup和unwind組合實現關聯查詢

MONGODB04 - 資料聚合Aggregation進階之lookup和unwind組合實現關聯查詢

前因

最近專案上又新需求了,相關的統計資訊介面,需要在MongoDB中實現類似mysql多表關聯查詢,那麼問題來了,MongoDB要如何才能像Hibernate那樣一對一,一對多對映關係了?本節講藉助loopup和unwind組合方式來實現此功能

需求

  1. 以勳章任務為主表查詢勳章任務名稱及相關配置資訊

  2. 匯出每個人任務下對應的檔案結果對比資訊

備註:涉及文件 Medal(勳章)、MedalTask(勳章任務)、MedalTaskFile(任務明細),文件從左到右一對多關係

實現

之前版本

實現思路

  1. 分頁查詢MedalTask,取出MedalId集合和taskIds集合

  2. 分別從Medal和MedalTaskFile查詢資料集合,進行二次聚合

Aggregation進階之lookup

先貼程式碼

/*資料聚合*/
Aggregation aggregation = Aggregation.newAggregation(
        Aggregation.match(criteria),
        /*關聯勳章*/
        Aggregation.lookup("medal", "medalId", "_id", "medal"),
        /*關聯任務*/
        Aggregation.lookup("medalTaskFile", "_id", "medalTaskId", "taskFiles"),
        /*查詢起始值*/
        Aggregation.skip(params.getPageNum() > 1 ? (params.getPageNum() - 1) * params.getPageSize() : 0),
        /*分頁大小*/
        Aggregation.limit(params.getPageSize()),
        /*排序*/
        Aggregation.sort(Sort.by(Sort.Order.desc("createdTime"))),
		/*打散Medal*/
        Aggregation.unwind("medal")
);
List<MedalUserTo> medalUserTos = medalV4MongoTemplate.aggregate(aggregation, MedalTask.class, MedalUserTo.class).getMappedResults();
@Data
private class MedalUserTo {
    private String medalId;
    private String userId;
    private Integer status;
    private Double rate;
    private Instant createdTime;
    private Instant submitTime;
    private Medal medal;
    private List<MedalTaskFile> taskFiles;
}

方法解讀

方法 引數 備註
match() (Criteria criteria) 查詢條件構建
lookup() (String from, String localField, String foreignField, String as) from:關聯表localField:主記錄關聯欄位,傳入的是MongoDB中的欄位名,非實體類欄位名foreignField:關聯表關聯欄位,欄位名同上as:別名,及實體類對映欄位名(lookup預設返回的型別是ArrayList,相關的欄位接收預設需要使用集合接收,類似一對多這種對映關係)
skip() (int elementsToSkip)(long elementsToSkip) 查詢起始值
limit() (long maxElements) 最大element數量,及分頁大小
sort() (Sort sort) 排序欄位
unwind() (String field) 展開這個欄位主要是用於聚合記錄拆分,把對應的集合欄位(長度為n)對應的主記錄拆分n個物件,欄位名對應是集中中單個文件物件本段程式碼使用場景,在已知一對一場景下,把lookup關聯的物件由陣列程式設計單物件(注:若不是一對一關係,則可能出現重複物件),所以在MedalUserTo中可以使用Medal物件接收該引數
project() (String... fields) 控制顯示查詢欄位,可用於返回指定欄位

unwind和project在MongoDB組合查詢示例

正常查詢

//正常記錄查詢,這裡遮蔽相關欄位,主要看資料結構
db.operationLog.aggregate([
	{$match:{_id:'DBDF7FA8C72C4606A15CF250FF35A530'}},
	{$project:{_id:1,batchIdList:1}}
])

結果

{ 
    "_id" : "DBDF7FA8C72C4606A15CF250FF35A530", 
    "batchIdList" : [
        {
            "taskId" : "721EB7250C0049B49A5AB4A734498F2B", 
            "batchInfos" : {}
        }, 
        {
            "taskId" : "E1C60CAD114D405B916E66A05256C07B", 
            "batchInfos" : {}
        }
    ]
}

使用unwind拆分查詢記錄

db.operationLog.aggregate([
	{$match:{_id:'DBDF7FA8C72C4606A15CF250FF35A530'}},
	{$unwind:"$batchIdList"}
])

結果

{ 
    "_id" : "DBDF7FA8C72C4606A15CF250FF35A530", 
    "batchIdList" : {
        "taskId" : "721EB7250C0049B49A5AB4A734498F2B", 
        "batchInfos" : {}
    }
}
{ 
    "_id" : "DBDF7FA8C72C4606A15CF250FF35A530", 
    "batchIdList" : {
        "taskId" : "E1C60CAD114D405B916E66A05256C07B", 
        "batchInfos" : {}
    }
}

對Aggregation的group、lookup、project和unwind方法進行靈活組合,大大精簡了我們對MongoDB的關聯查詢、統計查詢及相關聚合查詢等操作程式碼編寫