最近在專案中使用MongoDb先簡單介紹MongoDb
MongoDb是什麼?
MongoDB是一個基於分散式檔案儲存的資料庫。由C++語言編寫。旨在為WEB應用提供可擴充套件的高效能資料儲存解決方案。
MongoDB 是一個介於關聯式資料庫和非關聯式資料庫之間的產品,是非關聯式資料庫當中功能最豐富,最像關聯式資料庫的。
幹什麼?
這個簡單,肯定是儲存資料。MongoDB 將資料儲存為一個文件,資料結構由鍵值(key=>value)對組成。MongoDB 文件類似於 JSON 物件。欄位值可以包含其他文件,陣列及文件陣列。
怎麼用?
mongoDb的基礎操作命令
自行百度吧。。。
mongoDb菜鳥教程
專案中如何進行MongoDb的CRUD
可以使用兩種方式MongoRepository方式和mongoTemplate方式
MongoRepository方式
- 這種方式只有查詢和新增,而且只需要建立倉庫繼承介面MongoRepository,按照規則建立方法就行。
public interface LogRepository extends MongoRepository<Log>{
}
複製程式碼
看一下MongoRepository原始碼裡有什麼方法
@NoRepositoryBean
public interface MongoRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
<S extends T> List<S> save(Iterable<S> var1);
List<T> findAll();
List<T> findAll(Sort var1);
<S extends T> S insert(S var1);
<S extends T> List<S> insert(Iterable<S> var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
複製程式碼
- 所以save和findAll可以直接使用,Sort為排序。如果想根據條件查詢的話可以按照規則輸入方法名。當需要根據實體類中的屬性查詢時,MongoRepository提供的方法已經不能滿足,我們需要在Repository倉庫中定義方法,定義方法名的規則為:find + By + 屬性名(首字母大寫),例如:
/**
* 根據地址查詢
*
* @param address
* @author zyc
* @return
*/
List<AlarmLog> findByAddress(String address);
/**
* 根據地址查詢帶分頁
*
* @param address
* @author zyc
* @return
*/
Page<AlarmLog> findByAddress(String address, Pageable pageable);
複製程式碼
- 當需要根據實體類中的屬性進行模糊查詢時,我們也需要在PersonRepository倉庫中定義方法,模糊查詢定義方法名的規則為:find + By + 屬性名(首字母大寫) + Like
/**
* 根據地址查詢帶分頁
*
* @param address
* @author zyc
* @return
*/
Page<AlarmLog> findByAddressLike(String address, Pageable pageable);
複製程式碼
- 查詢指定的值在上面寫註解。其中value是查詢的條件,?0這個是佔位符,對應著方法中引數中的第一個引數,如果對應的是第二個引數則為?1。fields是我們指定的返回欄位,其中id是自動返回的,不用我們指定,json中{‘address’:1}的1代表true,也就是代表返回的意思。
@Query(value="{'address':?0}",fields="{'address':1}")
public Page<Person> findByAddressLike(String address,Pageable pageable);
複製程式碼
MongoTemplate方式
個人感覺這種方式更加全面一點,更好理解。
- pom引入mongoDB的依賴 pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
複製程式碼
- 配置檔案配置連線 application.yml:
server:
port: 8080
spring:
data:
mongodb:
uri: mongodb://localhost:27017/test01
application:
name: myserver
複製程式碼
- 在需要向mongoDB CRUD時引入MongoTemplate
@Repository("userDao")
public class UserDaoImpl implements UserDao {
/**
* 由springboot自動注入,預設配置會產生mongoTemplate這個bean
*/
@Autowired
private MongoTemplate mongoTemplate;
@Override
public void insert(User user) {
//插入資料id自增(mongoDB中存在自己的_id,如果不自己定義自增,會預設返回mongoDB中的_id,我看網上說是不建議將_id自增的,因為高併發會影響效能。從這看的https://segmentfault.com/q/1010000006019599)
mongoTemplate.insert(user);
}
@Override
public void update(User user) {
//根據id修改 update user set name=user.getName(),age=user.getAge() where id =user.getId()
mongoTemplate.updateFirst(new Query(Criteria.where("id").is(user.getId())),
new Update().set("name", user.getName()).set("age", user.getAge()), User.class);
}
@Override
public List<User> findAll() {
//select * from A
return mongoTemplate.findAll(User.class);
}
@Override
public User findOne() {
//select * from A LIMIT 1
return mongoTemplate.findOne(new Query(), User.class);// 第一條
}
@Override
public User findById(Long id) {
//Select * from A where a.id=id;
return mongoTemplate.findById(id, User.class);// id查詢
}
@Override
public List<User> find() {
//select name from A where name='10'
DBObject dbObject = new BasicDBObject();
dbObject.put("name", "10"); // 查詢條件
BasicDBObject fieldsObject = new BasicDBObject();
// 指定返回的欄位
fieldsObject.put("name", true);
return mongoTemplate.find(new BasicQuery(dbObject, fieldsObject), User.class);
}
@Override
public List<User> findOr() {
//select * from A where name='10' or age=13
return mongoTemplate.find(
new Query(new Criteria().orOperator(Criteria.where("name").is("10"),Criteria.where("age").is(11))),
User.class);
}
@Override
public List<User> findAnd(){
//select * from A where name='13' and id=1
return mongoTemplate.find(new Query(Criteria.where("name").is("13").and("id").is(1)), User.class);
}
@Override
public List<User> findOrAnd() {
//select * from A where a.id=1 and (age=9 or name =13)
return mongoTemplate.find(
new Query(Criteria.where("id").is(1).andOperator(new Criteria().orOperator(new Criteria().orOperator(Criteria.where("age").is(10),Criteria.where("name").is("13"))))),
User.class);
}
@Override
public List<User> findDayuXiaoyu(){
//select * from A where age>1 and age<10
//gte大於等於 lte小於等於
//ge大於 lt小於
//ne 不等於
Query ge_lt = new Query(Criteria.where("age").gt(1).lt(10));//大於等於
Query gte_lte = new Query(Criteria.where("age").gte(1).lte(10));//小於等於
Query ne = new Query(Criteria.where("age").ne(5));//不等於
return mongoTemplate.find(ne, User.class);
}
/**
* 模糊查詢 regex
完全匹配 "^hzb$"
右匹配 "^.*hzb$"
左匹配 "^hzb.*$"
雙開 "^.*hzb.*$"
*/
@Override
public List<User> findLike(){
Query query = new Query(Criteria.where("name").regex("^.*2$"));
return mongoTemplate.find(query, User.class);
}
@Override
public List<User> findInNot(){
//in 和not in
Query in = new Query(Criteria.where("age").in(5,6,7));
//in
Query notIn = new Query(Criteria.where("age").nin(5,6,7));
//not in
return mongoTemplate.find(notIn, User.class);
}
@Override
public List<User> findDie(){
Query findDie = new Query(Criteria.where("age").mod(9, 1));
//取模(取餘) age % 5==1
return mongoTemplate.find(findDie, User.class);
}
@Override
public List<User> findAllMatching(){
Query findAllMatching = new Query(Criteria.where("list").all(1L,2L));
//all 資料 [name=10, age=10, id=4, list=[1, 2]]
//完全匹配返回資料
return mongoTemplate.find(findAllMatching, User.class);
}
@Override
public List<User> findSize(){
Query findSize = new Query(Criteria.where("list").size(2));
//size 資料 [name=10, age=10, id=4, list=[1, 2]] 匹配陣列內的元素數量的 list.size =2 返回
return mongoTemplate.find(findSize, User.class);
}
@Override
public List<User> findExists(){
Query findExists = new Query(Criteria.where("list").exists(false));
//exists 判斷欄位是否為空 等同於sql的 list is null 和 list is not null
return mongoTemplate.find(findExists, User.class);
}
@Override
public List<User> findType(){
Query findType = new Query(Criteria.where("list").type(4));
//匹配資料型別
//Double 1 “double”
//String 2 “string”
//Object 3 “object”
//Array 4 “array”
//Binary data 5 “binData”
//Undefined 6 “undefined” Deprecated.
//ObjectId 7 “objectId”
//Boolean 8 “bool”
//Date 9 “date”
//Null 10 “null”
//Regular Expression 11 “regex”
//DBPointer 12 “dbPointer” Deprecated.
//JavaScript 13 “javascript”
//Symbol 14 “symbol” Deprecated.
//JavaScript (with scope) 15 “javascriptWithScope”
//32-bit integer 16 “int”
//Timestamp 17 “timestamp”
//64-bit integer 18 “long”
//Decimal128 19 “decimal” New in version 3.4.
//Min key -1 “minKey”
//Max key 127 “maxKey”
return mongoTemplate.find(findType, User.class);
}
@Override
public List<User> findNot() {
Query findDie = new Query(Criteria.where("age").not().mod(9, 1));
//not取反
return mongoTemplate.find(findDie, User.class);
}
@Override
public long count() {
Query count = new Query(Criteria.where("age").not().mod(9, 1));
//總條數
return mongoTemplate.count(count, User.class);
}
@Override
public List<?> distinct(){
return mongoTemplate.getCollection("User").distinct("name");
}
@Override
public List<?> sort(){
Query sort = new Query();
//排序
return mongoTemplate.find(sort.with(new Sort(Direction.DESC, "id")), User.class);
}
@Override
public List<?> limit(){
Query limit = new Query();
//分頁
//skip 設定起始數
//limit 設定查詢條數
return mongoTemplate.find(limit.skip(1).limit(3), User.class);
}
}
複製程式碼
複雜分頁查詢 我的理解這裡的query就是用來封裝查詢條件的 criteria.and().is() 在這裡是構建了一個精準查詢的條件,並且用 'and' 相連。
@Override
public Page<AlarmLog> findAlarmLog(LogCondition logCondition) {
log.info("進入查詢告警介面,請求引數LogCondition={}",JSON.toJSONString(logCondition));
int currentPage = logCondition.getCurrentPage();
int pageSize = logCondition.getPageSize();
Date startTime = logCondition.getStartTime();
Query query = new Query();
//設定起始數
query.skip((currentPage - 1) * pageSize);
//設定查詢條數
query.limit(pageSize);
Criteria criteria = new Criteria();
if (StringUtils.isNotEmpty(logCondition.getSystem())) {
criteria.and("system").is(logCondition.getSystem());
}
if (StringUtils.isNotEmpty(logCondition.getLevel())) {
criteria.and("level").is(logCondition.getLevel());
}
if (StringUtils.isNotEmpty(logCondition.getHostname())) {
criteria.and("hostname").is(logCondition.getHostname());
}
if (StringUtils.isNotEmpty(logCondition.getMessage())) {
criteria.and("message").is(logCondition.getMessage());
}
if (StringUtils.isNotEmpty(logCondition.getStatus())) {
criteria.and("status").is(logCondition.getStatus());
}
if (StringUtils.isNotEmpty(logCondition.getStartTime()) && StringUtils.isNotEmpty(logCondition.getEndTime())) {
criteria.and("createTime").gte(logCondition.getStartTime()).lte(logCondition.getEndTime());
} else if (StringUtils.isNotEmpty(logCondition.getStartTime())) {
criteria.and("createTime").gte(logCondition.getStartTime());
} else if (StringUtils.isNotEmpty(logCondition.getEndTime())) {
criteria.and("createTime").lte(logCondition.getEndTime());
}
query.addCriteria(criteria);
query.with(new Sort(Sort.Direction.DESC, "createTime"));
List<AlarmLog> alarmLogs = mongoOperations.find(query,AlarmLog.class);
log.info("查詢結果alarmLogs={}", JSON.toJSONString(alarmLogs));
int count = (int) mongoOperations.count(query, AlarmLog.class);
Page<AlarmLog> logPage = new Page<>();
logPage.setRecords(alarmLogs);
logPage.setTotal(count);
logPage.setCurrent(currentPage);
logPage.setSize(pageSize);
複製程式碼
這裡解釋一下,上面是最近做的一個查詢,是對多個欄位可能有可能沒有的分頁查詢,所以我只能用If做判斷處理,裡面有個查詢條件是個開始時間和截止時間內容。對一個欄位做兩次
criteria.and("createTime").gte()
criteria.and("createTime").lte()
複製程式碼
會報錯,所以使用了上面頗為醜陋的if else判斷。寫的時候查到了這種情況的處理方式,用到 andOperator 方法。試了一下可以。
//大於方法
Criteria gt = Criteria.where("createTime").gte("你的條件");
//小於方法
Criteria lt = Criteria.where("createTime").lte("你的條件");
/**
* new Criteria().andOperator(gt,lt) 把上面的大於和小於放在一起,注意上面兩個key一定是一樣的
* andOperator() 這個方法就是關鍵的方法了,把同key的多個條件組在一起
* 但是 andOperator() 有個很坑的地方就是,在一個query中只能出現一次
* 如果你有很固定很明確的入參,那還好,直接呼叫一次 andOperator()
* 如果是多個key需要多個條件,而且條件數量還是動態的,怕不是魔鬼吧...
*/
criteria.andOperator(gte, lte);
複製程式碼
按照慣例推薦一個軟體:wox(解放你的桌面,和上次說的everything一起使用,爽到嗨。可以自己網上搜最新版)
連結:pan.baidu.com/s/1KDXwbQyk… 提取碼:48b6