MONGODB04 - MongoDB關聯查詢,通過數據聚合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;
}

haha

方法解讀

方法 參數 備注
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個對象,字段名對應是集合中單個文檔對象
PS:本段代碼使用場景,在已知一對一場景下,把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的關聯查詢、統計查詢及相關聚合查詢等操作代碼編寫


免責聲明!

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



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