前言:
由於最近項目趕
,版本迭代快
,不知道大BOSS從哪裏聽別人說MongoDB用來做關係型數據庫好,而且速度快,性能高;聽到這話的我,立馬就反駁了回去:“MongoDB不支持事物”!
結果查閱了大量資料,反被大BOSS啪啪打臉…,哎…,最終還是本着爲大BOSS服務和學習的態度,技術選型上,關係型數據庫由MySQL
轉變成爲MongoDB-4.2
;
由於一時半會兒還不太適應MongoDB的一些寫法,查閱了大量的資料才搞定MongoDB在java中的實現方式,此次運用到的是spring的一個插件spring-data-mongodb
,版本號:2.2.6.RELEASE
;
使用spring-data-mongodb對mongo進行聯表分頁查詢
- MongoDB數據庫版本(已測試):
mongodb-3.4.0
及以上 - 安裝(單機版)教程:centos7 安裝MongoDB 4.2
- 安裝(集羣版)教程:centos7 單機搭建MongoDB 4.2.5副本集羣(支持事務)
- spring-data-mongodb maven依賴版本:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
1、一對一:兩張表關聯查詢,帶多條件查詢,分頁,排序
傳統的MongoDB的SQL語句實現
,如下:
db.shop.aggregate([
{
"$lookup":{
"from":"member", // 從表表名
"localField":"userId", // 如shop被查詢主表的userId,相對於member表的外鍵
"foreignField":"_id", // 如member從表的主鍵_id,相對於member表的主鍵
"as":"docs_member" // 聯合查詢出的別名,用於多條件查詢表明前綴,相當於SQL中的臨時表名
}
},
{
"$match":{
"shopStatus":1,
"blockade":{
// in包含查詢
"$in":[
0,
null
]
},
"dataFlag":1
}
},
{
"$skip":{
"$numberLong":"0"
}
},
{
"$limit":{
"$numberLong":"10"
}
},
{
"$sort":{
"modifyTime":-1
}
}
])
Java中實現以上寫法,如下:
package /**這裏是包名**/;
import com.sszh.mall.shop.entity.ShopDO;
import org.bson.types.ObjectId;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.regex.Pattern;
import org.springframework.data.mongodb.core.MongoTemplate;
public class ShopServiceImpl {
@Autowired
protected MongoTemplate mongoTemplate;
// 一對一:兩表關聯查詢
private List<ShopDO> twoTableQuery(String keyword, int pageNum, int pageSize) {
// TODO 店長是否實名認證
// 構建 Aggregation:添加查詢條件
Aggregation aggregation = Aggregation.newAggregation(
// 關聯member表
Aggregation.lookup(
"member", // 從表表名
"userId", // 如shop被查詢主表的userId,相對於member表的外鍵
"_id", // 如member從表的主鍵_id,相對於member表的主鍵
"docs_member" // 聯合查詢出的別名,用於多條件查詢表明前綴,相當於SQL中的臨時表名
),
// ============================================= 以上內容可舉一反三 =============================================
// 查詢條件
null == keyword || "".equals(keyword.trim())
?
Aggregation.match(
Criteria.where("shopStatus").is(1) // 店鋪狀態: 1:已審覈
.and("blockade").in(0, null) // 店鋪是否有效: 0=解封 -1=封鎖
.and("dataFlag").is(1) // 店鋪是否有效: 1:有效
.and("docs_member.telephone").is("8615323710096") // 添加member表查詢條件,如用戶手機號,此處可舉一反三
)
:
Aggregation.match(
Criteria.where("shopStatus").is(1)
.and("blockade").in(0, null)
.and("dataFlag").is(1)
// 根據店鋪名稱模糊搜索
.andOperator(Criteria.where("shopName").regex(Pattern.compile(keyword, Pattern.CASE_INSENSITIVE)))
),
// 分頁:頁碼
Aggregation.skip(Long.valueOf(pageNum)),
// 分頁:條數
Aggregation.limit((long) pageSize),
// 排序
Aggregation.sort(Sort.Direction.DESC,"modifyTime")
);
// 執行查詢,這裏的shop必須是查詢的主表名
AggregationResults<ShopDO> results = mongoTemplate.aggregate(aggregation, "shop", ShopDO.class);
return results.getMappedResults();
}
補充語法:
一對多關聯查詢(商品表爲主表、取商品規格集合
):
db.mall_goods.aggregate([
{
$lookup:
{
from: "mall_specs",
localField: "id",
foreignField: "goods_id",
as: "inventory_docs"
}
}
]);
一對多關聯查詢(訂單表爲主表,根據商品ID取商品名稱、商品規格集合
):
db.mall_order.aggregate([
{
$lookup:
{
from: "mall_goods",
localField: "id",
foreignField: "goods_id",
as: "goods"
}
},
{
$lookup:
{
from: "mall_specs",
localField: "goods_id",
foreignField: "goods_id",
as: "specs"
}
}
])
2、高級聚合查詢:排序:根據商品【銷售量 + 虛擬交易量】之和,進行倒敘排序(DESC):-1 降序 1 升序; 再根據價格,由小到大排序
傳統的MongoDB的SQL語句實現
,如下:
db.product.aggregate([
{
$project: {
_id : 1,
// ---------------- 部分代碼省略 ----------------
shopId: 1,
"saleNumCount" : {
$sum: ["$saleNum", "$salesVolumeNum"]
}
}
},
{
$sort: {"saleNumCount" : -1},
$sort: {"price" : 1}
}
// ---------------- 分頁代碼省略(注意:這整塊SQL語句都有先後順序要求) ----------------
])
備註:
- $project 屬性:設置返回指定字段
- 語句【 _id : 1 】解釋:此處的 1 代表返回,0 代表不返回
- 語句【 $sort: {“saleNumCount” : -1} 】解釋:根據統計結果從大到小排序
- 語句【 $sum: ["$saleNum", “$salesVolumeNum”] 】解釋:計算 【虛擬交易量 + 交易量】,發回字段 saleNumCount
Java中實現以上寫法,如下:
package /*包名省略*/
import com.alibaba.fastjson.JSONObject;
import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.sszh.common.core.MongoOperator;
import com.sszh.mall.product.entity.ProductDO; /*這個是返回的實體對象,不指定也可以*/
import com.sszh.mall.product.repository.ProductRepository;
import com.sszh.mall.shop.entity.ShopDO;
import com.sszh.mongodb.springdata.BaseMongoRepository;
import com.sszh.utils.DateUtil;
import com.sszh.utils.StringUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import java.math.BigDecimal;
import java.util.*;
public class ProductRepositoryImpl implements ProductRepository {
@Autowired
protected MongoTemplate mongoTemplate;
public MongoTemplate getDatastore(){
return mongoTemplate;
}
@Override
public List<ProductDO> getProductListByWhere(int categoryId,int pageNum,int pageSize) {
List<Document> pipeline = new ArrayList<>();
// 設置返回指定字段,1 返回 0/不指定 不返回
Document basicDBObject = new Document();
basicDBObject.put("_id", 1);
basicDBObject.put("shopId", 1);
basicDBObject.put("categoryId", 1);
basicDBObject.put("shieldSearch", 1);
basicDBObject.put("productName", 1);
basicDBObject.put("productPic", 1);
basicDBObject.put("price", 1);
basicDBObject.put("fare", 1);
basicDBObject.put("profit", 1);
basicDBObject.put("warnStock", 1);
basicDBObject.put("productStock", 1);
basicDBObject.put("isSale", 1);
basicDBObject.put("isBest", 1);
basicDBObject.put("productDescTitle", 1);
basicDBObject.put("productDescEnd", 1);
basicDBObject.put("saleNum", 1);
basicDBObject.put("saleTime", 1);
basicDBObject.put("dataFlag", 1);
basicDBObject.put("praiseNum", 1);
basicDBObject.put("forwardNum", 1);
basicDBObject.put("attributes", 1);
basicDBObject.put("forwardCommission", 1);
basicDBObject.put("createTime", 1);
basicDBObject.put("modifyTime", 1);
basicDBObject.put("salesVolumeNum", 1);
// 計算 【虛擬交易量 + 交易量】之和,返回字段 saleNumCount
basicDBObject.put("saleNumCount", new BasicDBObject("$sum", Arrays.asList("$saleNum", "$salesVolumeNum")));
Document project = new Document(MongoOperator.PROJECT, basicDBObject);
pipeline.add(project);
// 排序:根據商品【銷售量 + 虛擬交易量】之和,進行倒敘排序(DESC):-1 降序 1 升序; 再根據價格,由小到大排序
basicDBObject = new Document();
basicDBObject.put("saleNumCount", -1);
basicDBObject.put("price", 1);
Document sort = new Document(MongoOperator.SORT, basicDBObject);
pipeline.add(sort);
// 查詢條件
basicDBObject = new Document();
basicDBObject.put("isSale", 1); //查詢條件,狀態是否可用
basicDBObject.put("dataFlag", new BasicDBObject(MongoOperator.NE, -1)); //商品是否被刪除
basicDBObject.put("shieldSearch", new BasicDBObject(MongoOperator.NE, 1)); //商品是否可以搜索
Document match = new Document(MongoOperator.MATCH, basicDBObject); //將查詢條件添加到match中
pipeline.add(match);
// 分頁:開始位置
Document skip = new Document(MongoOperator.SKIP, (pageNum * pageSize));
pipeline.add(skip);
// 分頁:結束位置
Document limit = new Document(MongoOperator.LIMIT, ((pageNum + 1) * pageSize));
pipeline.add(limit);
// 執行聚合查詢操作:獲取數據庫連接、指定表名:product,發回結果集:cursor
final MongoCursor<Document> cursor = getDatastore().getCollection("product").aggregate(pipeline).iterator();
// 處理結果集
List<ProductDO> list = new ArrayList<>();
ProductDO productDO;
while (cursor.hasNext()) {
Document dbObject = cursor.next();
productDO = JSONObject.toJavaObject(JSONObject.parseObject(JSONObject.toJSONString(dbObject)), ProductDO.class);
productDO.setId((ObjectId)dbObject.get("_id"));
list.add(productDO);
}
return list;
}
}
mongodb 關鍵詞常量類:
package com.sszh.common.core;
public final class MongoOperator {
// id
public static final String ID = "_id";
// query condition
public static final String GT = "$gt";
public static final String GTE = "$gte";
public static final String LT = "$lt";
public static final String LTE = "$lte";
public static final String NE = "$ne";
public static final String IN = "$in";
public static final String NIN = "$nin";
public static final String MOD = "$mod";
public static final String ALL = "$all";
public static final String SLICE = "$slice";
public static final String SIZE = "$size";
public static final String EXISTS = "$exists";
public static final String WHERE = "$where";
public static final String REGEX ="$regex";
// query logic
public static final String AND = "$and";
public static final String OR = "$or";
// 2d and geo
public static final String NEAR = "$near";
public static final String WITHIN = "$within";
public static final String CENTER = "$center";
public static final String BOX = "$box";
// update
public static final String SET = "$set";
public static final String UNSET = "$unset";
public static final String INC = "$inc";
public static final String MUL = "$mul";
public static final String PUSH = "$push";
public static final String PULL = "$pull";
public static final String EACH = "$each";
public static final String POP = "$pop";
public static final String MIN = "$min";
public static final String MAX = "$max";
public static final String BIT = "$bit";
// aggregation
public static final String PROJECT = "$project";
public static final String MATCH = "$match";
public static final String LIMIT = "$limit";
public static final String SKIP = "$skip";
public static final String UNWIND = "$unwind";
public static final String GROUP = "$group";
public static final String SORT = "$sort";
}
參考文獻:
spring-data-mongodb官方參考文檔:
https://docs.spring.io/spring-data/mongodb/docs/3.0.0.RELEASE/reference/html/#mongodb.repositories.queries.aggregation
mongoTemplate.aggregate() 聚合查詢,關聯查詢:
https://blog.csdn.net/C18298182575/article/details/100698885
使用spring-data-mongodb對mongo進行聯表分頁查詢:
https://blog.csdn.net/qazwsx081/article/details/97897187
Spring Data Mongodb多表關聯查詢:
https://blog.csdn.net/zhang135123/article/details/85273957
SpringBoot整合MongoDB實現聚合查詢(多表聯查)以及一套簡單CRUD:
https://blog.csdn.net/weixin_44530530/article/details/91901631
MongoDB的多表關聯查詢:
https://blog.csdn.net/watersprite_ct/article/details/78500997
Spring Data Mongodb多表關聯查詢:
https://blog.csdn.net/zhang135123/article/details/85273957
Java使用mongodb進行數據存儲及多表關聯,多條件查詢:
https://blog.csdn.net/lchq1995/article/details/102586243
Spring Data MongoDB-參考文檔:
https://docs.spring.io/spring-data/mongodb/docs/2.2.3.RELEASE/reference/html/#mapping-usage
注:以上內容僅提供參考和交流,請勿用於商業用途,如有侵權聯繫本人刪除!
持續更新中…
如有對思路不清晰或有更好的解決思路,歡迎與本人交流,微信:seesun2012(非緊急項目請加QQ羣解答
),QQ羣:273557553
你遇到的問題是小編創作靈感的來源!