zoukankan      html  css  js  c++  java
  • 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与正则表达式联合使用时极为有效,用来查找那些与特定模式不匹配的文档。

  • 相关阅读:
    电脑页面放到手机显示时,遇到了一个奇怪的问题:字体的显示大小,与在CSS中指定的大小不一致
    Win 7 安装VMware Workstation Pro 14出现 “Intel VT-x禁用”问题以及“无法连接 MKS: 套接字连接尝试次数太多;正在放弃”问题的实质性解决
    linux下文件权限777了,file_put_contents()却不能写入,为什么?
    Linux常用命令版本CentOS7.x
    sqlserver阻塞
    深入理解sqlserver日志-01
    CentOS添加和删除用户
    root修改sudoers文件
    linux常用命令-持续更新
    CentOS虚拟机设置IP
  • 原文地址:https://www.cnblogs.com/duanxz/p/3606902.html
Copyright © 2011-2022 走看看