Java代碼通過org.springframework.data.mongodb.core.MongoTemplate對MongoDB的CRUD的操作,如果要實現復雜的條件查詢,需要通過Query類來實現。
一、Query類的使用說明
query查詢語句的實現的方式有兩種:
1.1、通過org.springframework.data.mongodb.core.query
構造函數
Query (Criteria criteria)
接受的參數是org.springframework.data.mongodb.core.query.Criteria
org.springframework.data.mongodb.core.query.Criteria:
Criteria是標准查詢的接口,可以引用靜態的Criteria.where的把多個條件組合在一起,就可以輕松地將多個方法標准和查詢連接起來,方便我們操作查詢語句。
例如: 查詢條件onumber="002"
new Query(Criteria.where("onumber").is("002"))
多個條件組合查詢時:
例如:onumber="002" and cname="zcy"
new Query(Criteria.where("onumber").is("002").and("cname").is("zcy"))
例如:onumber="002" or cname="zcy"
new Query(newCriteria().orOperator(Criteria.where("onumber").is("002"),Criteria.where("cname").is("zcy")))
我們通過Criteria的and方法,把這個條件組合一起查詢
Criteria提供了很多方法,我們這邊先介紹基本文檔的查詢操作符,對於數組文檔或者內嵌文檔的操作符,我們下一篇在介紹。
Criteria |
Mongodb |
說明 |
Criteria and (String key) |
$and |
並且 |
Criteria andOperator (Criteria… criteria) |
$and |
並且 |
Criteria orOperator (Criteria… criteria) |
$or |
或者 |
Criteria gt (Object o) |
$gt |
大於 |
Criteria gte (Object o) |
$gte |
大於等於 |
Criteria in (Object… o) |
$in |
包含 |
Criteria is (Object o) |
$is |
等於 |
Criteria lt (Object o) |
$lt |
小於 |
Criteria lte (Object o) |
$lte |
小等於 |
Criteria nin (Object… o) |
$nin |
不包含 |
。。。。。。。。。。。。。。 |
1.2、子類 org.springframework.data.mongodb.core.query.BasicQuery
構造方法
BasicQuery(DBObject queryObject)
BasicQuery(DBObject queryObject, DBObject fieldsObject)
BasicQuery(java.lang.String query)
BasicQuery(java.lang.String query, java.lang.String fields)
DBObject就是轉換成JSON格式,提供了我們回顧一下,MongoDB查詢時,
db.collection.find(query,projection),query類型是document,所以,我們想使用JSON字符串查詢時,我們使用DBObject創建查詢實例。
DBObject是接口,提供了幾個子類,
我們比較經常使用的比較底層子類,擴展了自己的方法和繼承父類,所以功能會比較多。
A. BasicDBObject
public class BasicDBObject extends BasicBSONObject implements DBObject, Bson {
例如:查詢條件onumber="002"
DBObject obj = new BasicDBObject(); obj.put( "onumber","002" );
相當於
db.collect.find({"onumber":"002"})
B. BasicDBList
public class BasicDBList extends BasicBSONList implements DBObject {
BasicDBList可以存放多個BasicDBObject條件
例如:我們查詢onumber=002 OR cname=zcy1
BasicDBList basicDBList=new BasicDBList(); basicDBList.add(new BasicDBObject("onumber","002")); basicDBList.add(new BasicDBObject("cname","zcy1")); DBObjectobj =new BasicDBObject(); obj.put("$or", basicDBList); Query query=new BasicQuery(obj);
相當於
db.orders.find({$or:[{"onumber":"002"},{"cname":"zcy1"}]})
basicDBList.add方法是添加一個文檔的查詢條件
C. com.mongodb. QueryBuilder
QueryBuilder默認構造函數,是初始化BasicDBObject,QueryBuilder多個方法標准和查詢連接起來,方便我們操作查詢語句。跟Criteria是標准查詢的接口一樣,
QueryBuilder和BasicDBObject配合使用
QueryBuilder幫我們實現了 $and等操作符,我們查看部分的源代碼:QueryBuilder部分的源代碼:
1.3、Query使用示例
Query query = new Query(); //搜索條件 if(null!=conditions.getAgentId()){ query.addCriteria(Criteria.where("agentId").is(conditions.getAgentId())); } if(null!=conditions.getOrderId()){ query.addCriteria(Criteria.where("orderId").is(conditions.getOrderId())); } if(null!=conditions.getOrderStatus()){ query.addCriteria(Criteria.where("orderStatus").is(conditions.getOrderStatus())); } if(null!=conditions.getAgentMemberId()){ query.addCriteria(Criteria.where("agentMemberId").is(conditions.getAgentMemberId())); } if(null!=conditions.getCustomerMemberId()){ query.addCriteria(Criteria.where("customerMemberId").is(conditions.getCustomerMemberId())); } if(null!=conditions.getPending()){ query.addCriteria(Criteria.where("orderStatus").is(0).orOperator(Criteria.where("orderStatus").is(1))); } // 排序 query.with(new Sort(new Order(Direction.DESC, "createTime"))); query.with(new Sort(new Order(Direction.ASC, "memberId"))); // 翻頁 PageCondition pageCondition = new PageCondition(pageNo, pageSize, ""); return memberDao.pageQuery(query, pageCondition); //翻頁場景 //不翻頁 //return memberDao.query(query, "");//第二個參數是國家碼,sprit17里可以傳""
二、find查詢時指定返回的需要的字段
org.springframework.data.mongodb.core.query.BasicQuery提供了
BasicQuery查詢語句可以指定返回字段,構造函數
BasicQuery(DBObject queryObject, DBObject fieldsObject)
fieldsObject 這個字段可以指定返回字段
fieldsObject.put(key,value)
key:字段
value:
說明:
1或者true表示返回字段
0或者false表示不返回該字段
_id:默認就是1,沒指定返回該字段時,默認會返回,除非設置為0是,就不會返回該字段。
指定返回字段,有時文檔字段多並數據大時,我們指定返回我們需要的字段,這樣既節省傳輸數據量,減少了內存消耗,提高了性能,在數據大時,性能很明顯的。
示例:
//查詢條件 queryBuilder.or(new BasicDBObject("memberName", memberNames.get(1)), new BasicDBObject("createTime", memberNames.get(2))); queryBuilder.or(new BasicDBObject("createTime", "002"), new BasicDBObject("createTime", "zcy1")); //返回字段列表 BasicDBObject fieldsObject = new BasicDBObject(); fieldsObject.put("onumber", 1); fieldsObject.put("cname", 1); Query query = new BasicQuery(queryBuilder.get(), fieldsObject); // 翻頁 PageCondition pageCondition = new PageCondition(pageNo, pageSize, ""); return pageQuery(query, pageCondition);
三、翻頁的性能問題
目前我們使用的是query.with(pc.getPageable()),看源碼其實就是最常見的分頁采用的是skip+limit這種組合方式,
public Query with(Pageable pageable) { if (pageable == null) { return this; } this.limit = pageable.getPageSize(); this.skip = pageable.getOffset(); return with(pageable.getSort()); }
skip+limit這種組合方式,這種方式對付小數據倒也可以,但是對付上幾百上千萬的大數據,只能力不從心,skip如果跳過大量的數據會很慢,並且會越查越慢。
// const list = db.getCollection('sent_logs').count({ field_1: 'wx5dacee99764a8af5' }).skip(200).limit(10);
針對這一情況,可以通過條件查詢+排序+限制返回記錄,即 邊查詢,邊排序,排序之后,抽取上一頁中的最后一條記錄,作為當前分頁的查詢條件,從而避免了skip效率低下的問題。
db.getCollection('sent_logs').find({ field_1: 'wx5dacee99764a8af5', key1:{$gt: '#上一條記錄的排序值#'} }).limit(20)
不過在項目使用過程中,發現后面的數據基本沒有用,所以用了一個閹割版的辦法,如果條目數大於特定值 比如5000條,則只返回前5000條,否則返回全部,即只能查看前5000條;
再想看更多結果的話 就得用縮小插敘范圍來解決了:
//代碼大概看下意思就行了 const total_count = 5000; const list = db.getCollection('sent_logs').find({ field_1: 'wx5dacee99764a8af5' }).skip(5000).limit(1); if (list.length === 0) { total_count = db.getCollection('sent_logs').count({ field_1: 'wx5dacee99764a8af5' }) }
這個方法雖然多了一次數據庫查詢,但是對於幾十萬往上的查詢結果分頁來說,提升的性能還是很客觀的。
2. 模糊匹配
2.1比較
> $gt , >= $gte, < $lt, <= $lte, != $ne
> db.tianyc02.find()
{ "_id" : ObjectId("50ea6eba12729d90ce6e3423"), "name" : "xttt", "age" : 111 }
{ "_id" : ObjectId("50ea6eba12729d90ce6e3424"), "name" : "xttt", "age" : 222 }
{ "_id" : ObjectId("50ea6b6f12729d90ce6e341b"), "name" : "xtt", "age" : 11 }
{ "_id" : ObjectId("50ea6b7312729d90ce6e341c"), "name" : "xtt", "age" : 22 }
> db.tianyc02.find({age:{$lt:100}})
{ "_id" : ObjectId("50ea6b6f12729d90ce6e341b"), "name" : "xtt", "age" : 11 }
{ "_id" : ObjectId("50ea6b7312729d90ce6e341c"), "name" : "xtt", "age" : 22 }
> db.tianyc02.find({age:{$lt:100,$gt:20}})
{ "_id" : ObjectId("50ea6b7312729d90ce6e341c"), "name" : "xtt", "age" : 22 }
> db.tianyc02.find({age:{$ne:11}})
{ "_id" : ObjectId("50ea6eba12729d90ce6e3423"), "name" : "xttt", "age" : 111 }
{ "_id" : ObjectId("50ea6eba12729d90ce6e3424"), "name" : "xttt", "age" : 222 }
{ "_id" : ObjectId("50ea6b7312729d90ce6e341c"), "name" : "xtt", "age" : 22 }
2.2 $in & $nin
> db.tianyc02.find()
{ "_id" : ObjectId("50ea6eba12729d90ce6e3423"), "name" : "xttt", "age" : 111 }
{ "_id" : ObjectId("50ea6eba12729d90ce6e3424"), "name" : "xttt", "age" : 222 }
{ "_id" : ObjectId("50ea6b6f12729d90ce6e341b"), "name" : "xtt", "age" : 11 }
{ "_id" : ObjectId("50ea6b7312729d90ce6e341c"), "name" : "xtt", "age" : 22 }
> db.tianyc02.find({age:{$in:[11,22]}})
{ "_id" : ObjectId("50ea6b6f12729d90ce6e341b"), "name" : "xtt", "age" : 11 }
{ "_id" : ObjectId("50ea6b7312729d90ce6e341c"), "name" : "xtt", "age" : 22 }
> db.tianyc02.find({age:{$nin:[11,22]}})
{ "_id" : ObjectId("50ea6eba12729d90ce6e3423"), "name" : "xttt", "age" : 111 }
{ "_id" : ObjectId("50ea6eba12729d90ce6e3424"), "name" : "xttt", "age" : 222 }
2.3 $or
> db.tianyc02.find({$or:[{age:11},{age:22}]})
{ "_id" : ObjectId("50ea6b6f12729d90ce6e341b"), "name" : "xtt", "age" : 11 }
{ "_id" : ObjectId("50ea6b7312729d90ce6e341c"), "name" : "xtt", "age" : 22 }
> db.tianyc02.find({$or:[{age:11},{name:'xttt'}]})
{ "_id" : ObjectId("50ea6eba12729d90ce6e3423"), "name" : "xttt", "age" : 111 }
{ "_id" : ObjectId("50ea6eba12729d90ce6e3424"), "name" : "xttt", "age" : 222 }
{ "_id" : ObjectId("50ea6b6f12729d90ce6e341b"), "name" : "xtt", "age" : 11 }
2.4 $not
> db.tianyc02.find({age:{$mod:[11,0]}})
{ "_id" : ObjectId("50ea6b6f12729d90ce6e341b"), "name" : "xtt", "age" : 11 }
{ "_id" : ObjectId("50ea6b7312729d90ce6e341c"), "name" : "xtt", "age" : 22 }
> db.tianyc02.find({age:{$not:{$mod:[11,0]}}})
{ "_id" : ObjectId("50ea6eba12729d90ce6e3423"), "name" : "xttt", "age" : 111 }
{ "_id" : ObjectId("50ea6eba12729d90ce6e3424"), "name" : "xttt", "age" : 222 }
$mod會將查詢的值除以第一個給定的值,若余數等於第二個給定的值,則返回該結果。
$not與正則表達式聯合使用時極為有效,用來查找那些與特定模式不匹配的文檔。