前言
最近學習使用mongodb中間使用關聯表查詢問題遇到一些問題記錄下來分享給大家。
mongodb關聯查詢
之前使用SQL語法來查詢oracle、sqlserver、mysql表之間的關聯,但是到mongodb之後完全無從下手,寫法完全不一樣,於是到網上查詢mongodb關聯表查詢的寫法,於是參考程式碼自己試著寫了下,但是發現有好多問題,比如我有兩個表user和apple,
user表:
id | name | age | createDt |
---|---|---|---|
ObjectId(1xxxx1) | zhangsan | 32 | |
ObjectId(2xxxx2) | lishi | 23 | |
ObjectId(3xxxx3) | wangwu | 19 | |
ObjectId(4xxxx4) | liuliu | 28 |
apple表:
id | uid | device | createDt |
---|---|---|---|
ObjectId(axxxxa) | 1xxxx1 | 10 | |
ObjectId(bxxxxb) | 2xxxx2 | 2 | |
ObjectId(cxxxxc) | 3xxxx3 | 7 | |
ObjectId(dxxxxd) | 4xxxx4 | 1 |
user實體類:
@Setter
@Getter
public class User {
private String id;
private String name;
private Integer age;
private Date createDt;
}
apple實體類:
@Setter
@Getter
public class Apple {
private String id;
private String uid;
private Integer device;
private Date createDt;
}
user和apple之間是一對一關係,現在我的查詢要求是:按device數量從大到小排序查詢使用者資料。
查詢結果應該是:
id | name | age | createDt |
---|---|---|---|
ObjectId(1xxxx1) | zhangsan | 32 | |
ObjectId(3xxxx3) | wangwu | 19 | |
ObjectId(2xxxx2) | lishi | 23 | |
ObjectId(4xxxx4) | liuliu | 28 |
我們分別使用user表和apple表做主表來查詢,那麼使用mongodb語法我們試著來寫一下。
以user表做主表查詢
// 1、新增_id欄位型別轉換
AddFieldsOperation addFieldsOperation = AddFieldsOperation.addField("_id").withValue(ConvertOperators.ToString.toString("$_id")).build();
// 2、按引數順序:被關聯表apple,主表user.id,被關聯表apple.uid,別名
LookupOperation lookupOperation = Aggregation.lookup("apple", "_id", "uid", "apple_as");
// 3、查詢哪些欄位,類似sql裡面的 select 選擇器
ProjectionOperation project = Aggregation.project("name","age","createDt").and("apple_as.device").as("device");
// 4、按照apple.device數量排序
// 注意:不能使用apple_as.device,並且 device欄位必須出現在project裡面,否則查詢失敗
SortOperation sort = Aggregation.sort(Sort.Direction.DESC, "device");
// 5、新增取List中
List<AggregationOperation> operationList = Lists.newArrayList();
operationList.add(addFieldsOperation);
operationList.add(lookupOperation);
operationList.add(project);
operationList.add(sort);
Aggregation agg = Aggregation.newAggregation(operationList);
// 因為返回的是User實體類,所以不會出現device欄位,你可以使用Map.class來返回想要的欄位
AggregationResults<User> aggregationResults = mongoTemplate.aggregate(agg, "user", User.class);
// 6、返回關聯查詢結果
List<User> dataList = aggregationResults.getMappedResults();
注意:我們在查詢之前要把主表的id轉換成String型別,因為被關聯表的uid就是String型別,否則查詢失敗
以apple表做主表查詢
// 1、新增uid欄位型別轉換
AddFieldsOperation addFieldsOperation = AddFieldsOperation.addField("uid").withValue(ConvertOperators.ToObjectId.toObjectId("$uid")).build();
// 2、按引數順序:被關聯表user,主表apple.uid,被關聯表user.id,別名
LookupOperation lookupOperation = Aggregation.lookup("user", "uid", "_id", "user_as");
// 3、查詢哪些欄位,類似sql裡面的 select 選擇器
// 注意:因為user是被關聯表,所以要使用user_as別名的方式來獲取使用者資訊欄位
ProjectionOperation project = Aggregation.project("user_as.name","user_as.age","user_as.createDt","device");
// 4、按照apple.device數量排序
SortOperation sort = Aggregation.sort(Sort.Direction.DESC, "device");
// 5、新增取List中
List<AggregationOperation> operationList = Lists.newArrayList();
operationList.add(addFieldsOperation);
operationList.add(lookupOperation);
operationList.add(project);
operationList.add(sort);
Aggregation agg = Aggregation.newAggregation(operationList);
// 因為返回的是User實體類,所以不會出現device欄位,你可以使用Map.class來返回想要的欄位
AggregationResults<User> aggregationResults = mongoTemplate.aggregate(agg, "apple", User.class);
// 6、返回關聯查詢結果
List<User> dataList = aggregationResults.getMappedResults();
注意:我們在查詢之前要把主表的uid轉換ObjectId型別,因為被關聯表的_id就是ObjectId型別,否則查詢失敗
總結
1、mongodb關聯查詢一定要注意ObjectId型別和String型別之間的轉換,否則不成功
2、project中出現的欄位會影響 sort排序
3、operationList的新增前後順序也會影響查詢
4、如果查詢失敗要多試幾遍,到底是哪一步出現的影響,我也是不斷的試錯才總結出來的。
5、如果有條件的話可以加如下程式碼:
AggregationOperation match = Aggregation.match(Criteria.where("uid").is(uid));
LimitOperation limit = Aggregation.limit(10);
operationList.add(match);
operationList.add(limit);
引用
Mongo學習筆記(三) 通過Aggregation和lookup進行多級關聯查詢
Springboot整合MongoDB系列(五)---LookupOperation關聯查詢