mongo-查詢


  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與正則表達式聯合使用時極為有效,用來查找那些與特定模式不匹配的文檔。

 


免責聲明!

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



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