mongodb笔记——查询

mongodb笔记——更新

本文为mongodb关于查询操作的知识点,更新操作的请查看上方链接。

以下举例操作集合为以下格式

student集合(不要太在意这表的设计,只是为方便举例而已)

_id name age sex score books
123 张三 20 man [{name:"语文",score:90},{name:"英语",score:90},{name:"数学",score:90}] ["java","OC","js","mongodb"]

1、普通查询

mongodb使用的是bson,使用上跟jison几乎无异,在使用查询上基本跟操作对象差不多
(1)查所有数据
db.student.find()

(2)只查询指定的字段
db.student.find({},{name:1})

db.student.find({},{name:0})


上面例子中第一个{}为条件,第二个为要查询的字段0为不显示,1为显示。
第一条查询结果只显示_id和name,如要_id也不显示则需要指明_id不显示(即{name:1,_id:0}),第二条的查询结果则为除了name,其他的都显示。

2、简单条件查询

(1)等于查询
db.student.find({age:20})

db.student.find({age:20},{name:1,sex:1})

第一条语句查询所有age等于20的数据,且显示所有字段。第二条语句则是查询age等于20的数据,且只显示_id,name和sex

(2)范围查询
从上面的例子可看出所有的数据操作中是以键值对的形式操作的,所以很明显mongdb不能>,<,!=等这些比较符,而是使用以下比较符
sql mongdb
> $gt
< $lt
>= $gte
<= $lte
!= $ne
in $in
not in $nin

例子
//age不等于20的记录
db.student.find({age:{$ne:20}});

//age等于19,20,21的记录
db.student.find({age:{$in:[19,20,21]}});

3、多条件查询

多条件查询连接符无非就是and 和 or 操作
and操作在mongodb中很简单,他的查询条件为键值对(个人理解为JS中对象的操作,即如查age=20,name=张三的记录则是传个对象student,其age属性为20,name为张三,所以为{age:20,name:"张三"}。同理可得or操作,则需要多个对象,如查age为20,或name为张三的记录,则需{age:20}和{name:“张三”}两个对象,这个了解持久层框架的同学应该很容易理解的),所以and多条件查询,只需将条件用,隔开即可。
而or不要尝试也用,隔开如db.student.find({age:21,age:20}),这句的查询结果只为age=20的记录,要进行or查询则需要操作符$or,进行连接
例子:
//查询age=20 and name=zhangsan
db.student.find({name:"zhangsan",age:20});

//查询age=20 or name=zhangsan
db.student.find($or:[{name:"zhangsan"},{age:20}]);

//查询age=20 or (name=zhangsan and age=21)
db.student.find($or:[{age:20},{name:"zhangsan",age:21}]);

//查询age=20 and (name=zhangsan or name=lisi)
db.student.find({age:20,$or:[{name:"zhangsan"},{name:"lisi"}]})

4、模糊查询

模糊查询,mongodb并没有sql的like语句,但相对应的它支持更强大的正则表达式,使用正则表达式进行模糊查询,有两种方式第一种关键注意点1、不需要 “ ”,2、使用 /  开始和结束标记。第二种使用关键词$regex
例:
//name包含“李”字
db.student.find({name:/李/})

//name包含“李”字,第二种写法
db.student.find({name:{$regex:"李"}})


//name为z开头,n结尾
db.student.find({name:/^z.*n$/})

//name不含有"李"字
db.student.find({name:{$not:/李/}})


 
   
 
   
 
   
 
   
 
   
 
   
 
   
 
  

5、复杂查询,可使用$where

mongodb可使用js语句,在做复杂查询的时候,可以使用js进行筛选,db.student.find({$where:function(){}}),其中function返回true则为所需要的记录。例
//查询数学成绩大于80的记录
db.student.find({$where:function{
    var score=null;
    for(var i=0;i<this.score.length;i++){
        score=this.score[i];
        if(score.name==="数学" && score.score>80){
           return true;
        }
     }
     return false;
}});
 
   
 
   
 
   
 
   
 
   
 
   
 
   
 
  
上面的this为集合中的一条记录。(mongodb叫decument,在本文中因为sql的习惯,有些地方都没使用mongodb的名词,大家理解就行了,像数据表mongodb叫集合)

6、游标  

上面说了,mongodb在shell中支持js,那么当我们执行语句 var s=db.student.find(); 后,s不是为student数组而是游标,但也支持使用s[i]来获取对应的记录。
需要注意以下几点:
(1)获取记录的数量:s.size(),s.length(),s.count(),都可以获取数量,其中size()内部是调用了count(),所以size()和count()是一样的。与length()的不同点是。。。。。。不知道怎么描述,举个例子
var cursor=db.student.find({age:20});

print(cursor.size());//结果20
print(cursor.length());//结果20

var s=cursor.next();
db.student.update(s,{$set:{name:"test"}});

print(cursor.size());//结果20
print(cursor.length());//结果20


var s=cursor.next();
db.student.update(s,{$set:{age:22}});

print(cursor.size());//结果19
print(cursor.length());//结果20
从例子可看出,当你更新的属性与你查询条件无关时length和size是一样的,但当你更新的属性是你的查询条件时,即修改后该条记录就不满足你之前的查询条件了,那么size的结果就不包含该记录,就是例子中最后的结果为19。这两个分别可以用于length初始满足条件的条数,size用于update后还满足条件的记录条数。(有兴趣的同学就去输出cusrsor的这三个集合长度的方法看看分别的实现方式有什么不同,这里就不多讲了,因为shell是支持js的,cusrsor也是一个对象,所以输出方式跟js的一样)

(2)是否有下条记录:s.hasNext(),true即表示有下一条
(3)游标移到下一条记录:s.next();
(4)游标销毁条件1、客户端主动销毁,2、游标迭代完毕(即s.hasNest()为false时,经测试直接输出s和获取s[s.size()]时也为迭代完毕)。3、默认超过10分钟没有
(5)经测试在迭代完毕后确实使用p.hasNext()为false,p.next()也获取不到数据,但获取长度和使用下标获取数据是可以的即s.size().和s[i]是可以获取到数据的,所以可以使用js进行for循环再次获取对应的数据。但我不知道有没有时间限制靠不靠谱。

7、数据内的数组及文档查询

有时候我们的某些字段是存一个数组或一个对象(这是比sql强的地方),那么我们就需要对内部的值进行查询,比如现在的student集合,我们需要查询有java这本书的记录,或要查询数学成绩为90的记录,对于数组内值的匹配有对应的$in,$nin,$not,$all,$size,$slice前面三个我们就不说了跟前面的应用差不多,$all操作符的意思是数组中包含所给条件的记录,$size是查询数组的长度等于条件的记录,但他不支持小于大于操作,所以一般是以数组中第n个值存不存在来做小于大于的判断,也可以使用上面提到的$where,进行判断。$slice则是用于限定输出,比如我只想看books的第0到1本书是什么就可以使用这个。
例:
//查询第一本书是java的记录,注意这里的books.1要用双引号括起来
db.student.find({"books.1":"java"})

//查询数组中包含java和mongodb的记录
db.student.find({books:{$all:{"java","mongodb"}}})

//查询数组中包含java或mongodb的记录
db.student.find({books:{$in:[java","mongodb"]}})

//查询数组长度为4的记录
db.student.find({books:{$size:4}})

//查询数组长度小于3的记录,index从0开始,所以books[2]不存在则长度小于3
db.student.find({ "books.2": {$exists:0} })

//查询数组长度大于3的记录,index从0开始,所以books[3]存在则长度大于3
db.student.find({ "books.3": {$exists:1} })

//使用$where查询数组长度大于3的记录
db.student.find({$where:"this.books!=null && this.books.length>3"})

//只查看前两本书名
db.student.find({},{books:{$slice:[0,2]}})

//只查看最后一本书
db.student.find({},{books:{$slice:-1}})


查数组的对象,先来例子
//1、查询数学成绩80的,普通写法
db.student.find({score:{name:"数学",score:80}})

//2、查询有成绩有80的,优化写法
db.student.find({"score.score":80})

//3、查询语文80的,错误写法
 db.student.find({"score.name":"语文","score.score":80})

//4、查询成绩有80的,推荐写法
db.student.find({score:{$elemMatch:{name:"语文",score:80}}})




第一条例子,普通写法,这么写没什么问题,但是如果你要查询成绩中有80分的,那么你就要进行一次或操作,数学80或语文80或英语80,科目越多,语句越长。所以复杂的对象不利使用。

所以有优化例子2,直接指明成绩80分的,这里需要注意的跟数组的下标一样,score.score要用双引号扩起来。

看到例子2,有人可能就会出现例子3,这种写法了,其实这个语句是错误的,比如有两条数据第一条是[{name:“语文”,score:90}],第二条[{name:“数学”,score:80}],根据例子3的写法,mongodb会先拿第一个条件"score.name":"语文"跟第一条记录匹配,为正常,第二个条件"score.score":80不匹配,然后就会跳到第二条记录,因为"score.name":"语文"在第一条记录时已匹配,所以到第二条时他直接验证"score.score":80,匹配,那么第二条记录就会查询出来了,但实际上这查询结果是错误的。

正确的写法是使用例子4,$elemMatch是对每个属性的匹配,相当于例子1的简写,有人会说这是什么简写,反而更长了,是的,在当前的例子中是更长了,但如果是条件多的话就会变得简便了,比如有查询语文或数学为80的,只需加个in或or,即db.student.find({score:{$elemMatch:{name:{$in:["语文","数学"]},score:80}}})即可,对比第一个例子的写法就需要or两个对象,如果对象的属性很多那就是个坑了。


8、分页、排序

这个比较简单,分页跟mysql差不多,分页利用限制条数limit(),和跳过条数skip()实现,排序则是使用sort(),1为升序,-1为降序。例:
//只查前2条
db.student.find().limit(2);

//查前3和4条
db.student.find().limit(2).skip(2);

//根据age升序排序
db.student.find().sort({age:1})
但实际上数据量比较大查询比较频繁时跳过条数mongodb不推荐使用skip,更推荐使用比较大小,比如按根据创建时间排序分页,那么直接查询比上次查询最后一条数据的创建时间小的数据即可。
还有一点mongodb跟js一样对于对象是弱类型,即使age属性,你也可以存整形,字符串、数组甚至null都可以,所以对于不同类型就有排序的优先级了,这里不写了,直接找个图贴上来:

9、多表查询


to be continued。。。。。


发布了13 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/lanqi_x/article/details/74858823
今日推荐