shell脚本中mongoDB查询详解

本篇博文主要讲述, shell中查询命令, 如何跟标准sql一样添加各种筛选条件, mongodb中游标的使用等功能,从而弄清楚,mongo是如何驾驭复杂查询和简单查询的

1. 基本的查询shell命令 :“find"或"findOne”

  • findOne和 find
    mongoDB中查询命令是find ,基本语法如下
    db.collectionName.find()
    
    上边的语句会返回这个集合中所有的document , 上边的语句中没有指定document , 默认就是
     db.collectionName.find({})
    
    如果想要查询比如 , age是14的学生,可以采用下边这种方式,
     db.student.find({age : 14})
    
    类似上边的方式 , 可以向查询文档加入多个键值对, 将多个查询条件组合在一起,相当于是sql语句中 条件1 and 条件2 and … 。 比如查询 14岁的高一二班的李姓同学
    db.student.find({‘age’ : 14, ‘grade’ : '高一',class:‘四班’,‘firstName’ : '李'})
    
    对于搜索,可以和sql一样,指定需要返回的键,一些不需要的 key, 可以采用下边的方式
     db.student.find({‘age’ : 14},{"grade":1,"email":1})
    
    上边语句的意思是 只返回 grade和email两个字段,当然,_id 字段是默认返回的 。 等于 1 是默认返回,同理, 如果不想结果document中返回某个字段,可以用 等于 0, 比如
     db.student.find({‘age’ : 14},{"age":0}) // 不想要 age字段
    

2. 使用"$"条件查询

  • 筛选条件
    上边的查询,只能返回一些某个字段等于多少的 document ,但是对于常用的一些查询,没法做到,比如一些范围查询、不等式查询、包含查询等。而这些查询就需要用到条件查询
    常见条件如下表

    查询符 说明 例子
    范围查询条件 大于: “$gt” 、小于 : “$lt”、大于等于:"$gte"、小于等于:"$lte"、不等于:"$ne" {“name”:{"$ne": ‘aa’}}
    或者查询 “$or” 可以把多个条件组合起来,查询一个字段多个值用in;查询多个条件字段 。用法和其他不一样, 直接组合条件· {"$or":[{“name”:‘zhangsan’},{“age”: 14}]}
    范围查询 “$in” 相当于是sql中in条件,查询一个字段包含多个值 ; {“z”:{"$in":[1,2,3]}}
    否条件 “$not” 元条件句,可以用在任何其他条件上 ,常与正则表达式结合使用 {“z”:{"$not":{{"$in":[1,2,3]}}}}
    空值查询 和sql不太一样,查询空值需要做到两步 : 判断键值为空 + 判断是否存在这个键 “$in” + “$exists” {“z”:{"$in":[null],"$exists":true]}}
    正则表达式 标准sql中没有的功能,查询某个字段值符合某个正则表达式 ,类似sql中模糊查询 {“name”:/Joe/i}

    上边的列表简单整理了,常用的mongodb的查询筛选条件,和sql一样,它们也可以做到组合

    • 多个条件的组合 : ”$or“ 和 ”$and“
       {"$and":[条件1,条件2...]}  // 条件1 、条件2 都是用大括号圈起来的条件, 比如{name: 'zhangsan'}
      
    • 范围筛选 : 大于、小于等 基本语法
      {"salary":{"$gt":5000}}  // : 一般是 {"字段":{"大于或者小于等":”一个值“}}
      
    • 查询一个字段多个值 : ”$in“ ,和数组中所有值都不匹配用”$nin“
      {"salary":{"$in":[5000,50000,500000]}}  // : 一般是 {"字段":{"$in":[一个数组]}}
      
    • not : 否定
      比如一个字段不是多少 (可以用”$ne“,这里只是为了演示)
      {name:{"$not":{"$eq":'zhangsan1'}}} // 注意 : 下边写法就是错误的
      //  {"$not":{name:{"$eq":'zhangsan1'}}} 
      
  • 查询特定的值

    • 查询空值
      对于mongoDB来说,查询空值不能只用null, 它不止查询对应key为空的,也查询没有这个key的,所以需要组合”$exists“ (是否存在), 比如
        db.peole.find({"lover":{"$in" : [null] ,  "$exists" : true }})
      
  • 正则表达式查询
    mongoDB可以为前缀性正则表达式创建索引 (比如 /^abc/), 换句话说,这样的查询会非常高效,为提高效率,可以研究一下 。 一般没人会把正则表达式本身当做字符串插入数据库, 不过,若有此类数据,正则表达式查询也会把这条记录查询出来

3. 键是属于内存还是外层文档

  • 键的使用位置
    在上边的例子中,我们发现”除了and、all 所有的条件都是表示字段 满足什么的 (放到字段里边一级“ ,比如
     {name:{"$not":{"$eq":'zhangsan1'}}}  // not是放在文档内部的(字段名在外边)
      {"$and":[{"name":1},{"age":14}]}  // and是放在文档外部的
    
    实际上查询条件一般放在文档内部,除了 “$and”、 “$or”。 因为这俩个表示多个条件的组合。这也符合对于查询的设定,查询肯定是某个字段满足什么条件 ,或者满足哪几个条件(and、or)
    对于赋值来说,和查询不一样,之前看 高阶增删改中发现, 条件一般放到外层,比如
    {"$set":{"lover":'宝贝'}}
    {"$push":{"lover":"honey"}}
    

4. 查询数组

  • 数组中搜索条件
    • 查询单条记录,可以直接用find (document)的方式,举例如下

      	db.people.insert({lover:['小梦','莹莹'], name : 'joe'})
      	db.people.insert({lover:['小玉','莹莹'] ,name : 'tony'})
      

      如果查询喜欢小玉的,可以用 下边的语句, 会把向匹配的记录查询出来

      > db.people.findOne({lover : '小玉'})
      {
      	"_id" : ObjectId("5d8a0d92fa4e34df34f24a06"),
      	"lover" : [
      		"小玉",
      		"莹莹"
      	],
      	"name" : "tony"
      }
      
    • 查询同时满足多个条件的, 可以用 ”$all“
      比如查找既 喜欢小玉、又喜欢莹莹的,可以用下边的语法

      >db.people.findOne({"lover":{"$all":['小玉','莹莹']}})
      {
      	"_id" : ObjectId("5d8a0d92fa4e34df34f24a06"),
      	"lover" : [
      		"小玉",
      		"莹莹"
      	],
      	"name" : "tony"
      }
      

      当然,使用上边说的精确匹配也可以查询出来, 两者区别是 : 精确匹配只查出完全符合要求的, ”$all“ 只要同时有查询的值的记录都查询出来,例如, 下边的三条数据

      db.people.insert({lover:['小梦','莹莹'], name : 'joe'})
      db.people.insert({lover:['小玉','莹莹'] ,name : 'tony'})
      db.people.insert({lover:['小梦','莹莹','小玉'], name : 'bob'})
      

      用精确匹配,只能查询出tony , 用all会查询出tony和bob

      db.people.findOne({"lover":{"$all":['小玉','莹莹']}}) // 查询结果 tony和bob
      db.people.findOne({"lover":['小玉','莹莹']}) //只会查出tony
      
    • 查询特定长度数组 ”$size“

      查询数组元素个数是n个的,可以使用, 比如查询有三个爱好的成员的筛选条件。
      数据格式

      {
        name : 'zhangsan', hobby : ['look','eat']
      }
      {
        name : 'lisi', hobby : ['look','eat','read']
      }
      {
        name : 'wang', hobby : ['play']
      }
      

      查询条件

      {"hobby":{$size : 3}}
      
    • 返回满足 “一定数值范围内的” 的 document
      比如下边的数据格式

      	{x: 5}
      	{x: 15}	
       	{x: [5,25]}		
      

      查询值在 10到 20之间的, 直接用之前的范围查询条件,在数组身上并不适用

      >db.test.find({x:{"$gt":10,"$lt":20}})
      {x: 15}	
      {x: [5,25]}		// 这一条也会被查询出来
      

      查询多出来一条,因为数组这样理解 大于10 条件第三条满足(25)、小于20的条件第三条文档也满足(5),所以,范围查询条件,对数组无效,因此引入 ”$elemMatch“ ,是查询条件的两个语句和一个数组元素进行比较,例如

      { _id: 1, results: [ 82, 85, 88 ] }
      { _id: 2, results: [ 75, 88, 89 ] }
      
       { results: { $elemMatch: { $gte: 80, $lt: 85 } } 
      

      $elemMatch查询满足多个条件的,数组元素 。 如果有多个匹配的元素,只查找第一个

5 查询中游标的应用

- 游标
	对于数据库来说,利用游标返回find的执行结果,客户端对有标的实现可以做到对最终结果做到有效控制,比如排序,限制数量,省略结果。 比如 mysql中 order by 、limit等

 - mongo shell中使用游标
 	shell中 find()方法返回的就是游标对象,示例如下
 	```json
 	var cursor = db.people.find();
 	cursor.forEach(function(x){
 		print(x.name)
	})
 	```
 	调用find(),shell不会立刻查询数据库,是在真正要求获得结果时,才会查询,所以,可以给查询添加一些额外的选项,甚至可以做到链式调用,比如
 	```json
 		var cursor = db.people.find().sort({"x":1}).limit(1).skip(10) // 这三个条件没有先后顺序
 	```
 	mongo此时还不会执行查询,只是在构造查询,设执行下一步,需要结果集了,比如
 	```json
 		cursor.hasNext()
 	```
 	这时,查询会被发往服务器,shell会立刻获取前100个结果或者前4M的数据(取最小值), 这样下次调用next不会再查询服务器 (书中这样写的,数值可以自己测试一下),用光了这批结果,再去查询数据库,使用getMore请求查询更多结果,这个过程会持续到游标耗尽或者结果全部返回

6 . 针对游标的一些操作

  • 常用的限制选项
    比如限制返回的数量、忽略一定数量的结果、进行排序。相关的函数如下

    db.people.find().limit(3)  //限制最多返回3条,
    db.people.find().skip(3)  //跳过前三条,返回剩下的,
    db.people.find().sort({name:1,age:-1})  //1是升序,-1是降序
    
  • 可以利用这些条件实现分页,比如

    // 注意 : skip ()跳过很多文档,会很慢,不建议用,只是了解
    db.people.find().limit(15)  //第一页
    db.people.find().limit(15).skip(15)  //第二页
    db.people.find().limit(15).skip(30)  //第三页
    
  • 游标的生命周期
    看待游标可以从两个角度 : 客户端的游标、与之对应的数据库游标
    在服务器端,游标消耗内存和其他资源,游标遍历尽了结果以后,或者客户端发来消息要求终止,数据库会释放这些资源,换句话说,要尽量保证合理快速释放游标
    此外 :绝对多数驱动程序实现了 immortal的函数,来告知服务器游标超时,做到超时销毁

7 . 驱动程序

  • 高阶查询
    实际上,绝大多数的驱动程序都提供了辅助函数,用于想查询中添加各种选项

你可能感兴趣的:(后台眼中的Mongo)