MongoDB的用法集锦:查询篇----->持续更新中
实验环境: mongodb3.2
使用mongodb可以使用k-v演算的含义对以前的关系SQL进行改写
但是也有一些陷阱,并不是照猫画虎就可以的。
因为mongodb是非关系型数据库,一些关系性的东西需要我们靠逻辑进行维护
使用sql,首先要会这个CRUD操作
记住mongodb中基本的存在是文档,所以条件呀,值什么的都要以文档的形式表现出来
1--查询
1.1常用的条件语义操作符
记忆要点: 条件限制是条件语义,大部分操作符是处于表语位置,所以大部分操作符是在属性名字的后面
但是也有一些是在前面的,主要是他们后面的值都是数组。
有一部分的操作符的值是开关,也就是true和false,但是书上写的是1或者0,其实使用true和false更好一点
数组的是特殊的文档,可以使用条件定位和位置定位
a: 常见的条件操作符
$gt,$lt,$gte,$lte,$ne,$all,$exists,$mod,$in,$nin,$nor,$or,$and,$size,$sort,$each,$slice,$where
b: 操作符在前面的,他们的值是数组
$and ,$or,$nor
$and:[{//条件文档1},{//条件文档2},{//条件文档3}...]
$or:[{//条件文档1},{//条件文档2},{//条件文档3}...]
$nor:[{//条件文档1},{//条件文档2},{//条件文档3}...]
另外值是数组的还有这个 $each和$mod,但是他们是属性后面的存在
$skill:{$each:['java','c++']}
$num:{$mod:[2,0]} //num%2==0
c: and 的语义使用,即可,但是也可以使用$and 进行描述
$and:[{a:{$lt:8}},{b:{$gt:5}}]
d:一切的条件都可以使用$where来进行描述
$where:function(){
return this.xxxx的条件表达式
//this就是当前的文档
}
使用例子:
1:等于语义 select * from test.person where name = 'fengk'
>use test
>db.person.find({name:'fengk'})
>db.person.find({name:{$in:['fengk']}});
>db.person.find({$where:function(){
return this.name=='fengk';
}})
2:且的语义 select * from test.person where index >3 and index<=8
>db.person.find({index:{$gt:3,$lte:8}})
>db.person.find({$and:[{index:{$gt:3}},{index:{$lte:8}}]})
>db.person.find({$where:function(){
return this.index >3 && this.index<=8
}})
错误的用法
从上面可以看到这个,在文档中是有且的概念的,因此使用,来分隔就是且的语义
但是这个只能适用于不同的key,同一个key使用的时候只能写一个key,不能重复
例如:
>db.person.find({index:{$gt:3},index:{$lte:8}})
这种写法将这个index出现多次的时候,最后的结果只是最后的 index:{$lte:8}起的限制作用
这个时候只能把key写成一个
例如描述这个 select * from test.person where index =4 and index <7
等于的语义本身是: 进行解释的,但是处于复合条件中的等于,由于key不能重复只能使用这个 $in来进行描述了
>db.person.find({index:{$in:[4],$lt:7}})
可以使用$and 但是它是不被优化的,所以效率上不能保证。
3:且的语义 select * from test.person where index <7 and kind='B'
>db.person.find({index:{$lt:7},kind:'B'})
4:in的语义 select * from test.person where index in(3,5,8)
>db.person.find({index:{$in:[3,5,8]}})
5: or的语义 select * from test.person where index =2 or kind = 'C'
>db.person.find({$or:[{index:2},{kind:'C'}]})
6:限制输出列表 select index,kind from test.person where kind !='C'
>db.person.find({kind:{$ne:'C'}},{index:1,kind:1,_id:0})
注意只要把这个输出的列表项设为1就可以了,但是有一个例外那就是这个_id ,所以把_id要设为0
前面说过这个1和0是开关的时候使用true和false更为贴切,这样不用和其他的值弄混
用true和false来写更为合适
>db.person.find({kind:{$ne:'C'}},{index:true,kind:true,_id:false})
7:null查找 select * from test.person where info is null
>db.person.find({info:null})
上面的写法是逻辑不完善的,因为这个info属性不存在的文档也是符合这个条件的。
所以还要加上这个存在的限制条件
>db.person.find({info:{$in:[null],$exists:true}})
8:容易出错的元操作符 $not
这个操作符是可以作用与其他的条件操作上面的,但是要注意它只是条件表达式中可以限制
比如 $lt ,$mod,$ne 等等
对于$and ,$or ,$nor这种处于前面的操作符不能给他么限制
例如 $not:{$and:[....]} 这种写法是错误的。
$not也只能和其他一般的语义操作符一样位于属性的后面
>db.person.find({kind:{$not:{$ne:'A'}}})
1.2数组的查询
a: 条件操作符
数组的值 可以看成是特殊的k:V结构
也就是一个key有多个值的情况
{kind:['A','B','C']}
可以理解成这个多值的情形
{kind:'A','B','C'}
这样以来对于数组的查询和一般的条件的语义查询没有其他的区别
>db.person.find({kind:'B'})
你看这种写法和一般的没有区别吧。
但是反过来思考下:这种方便性也带来其他的困扰
给定条件 db.person.find({kind:'B'})
我们不能区分它到底是一个一般的条件,还是数组的条件
如果我们的条件逻辑不严密,那么数组中满足改条件的元素存在的话,数组也是可以被过滤出来
我们的逻辑此时就要考虑到数组的情况
b: 数组全部匹配
>db.person.find({kind:['A','B','C']})
c: 数组子集匹配,使用 $all
>db.person.find({kind:{$all:['B','C']}})
d: 长度匹配,使用$size,但是$size不能和$gt,$lt等结合使用
>db.person.find({kind:{$size:3}})
e: 切片操作,$slice
如果你接触过这个python就知道可迭代对象的切片思想了
$slice:[offset,len]
如果这个offset为0的时候也可以省略为 $slice:len
也就是截取 [offset,offset+len)区间的元素角标指定的元素子集合
其中这个len可以是负号
+len表示从元素0开始截取
-len表示从数组末尾反向截取
但是注意这个使用的时候它有些特殊。
如果按照一般的使用方法用会报 unknown operator: $slice
比如 > db.person.find({index:6,comments:{$slice:2}})
使用find的时候,它的第二个参数是要返回的键,也就是查询的列表项目
但是如果使用这个$slice的时候,它出现在第二个参数中,用于指定一个数组元素要返回一个子集数组
所以这个操作符必须出现再find的第二个参数中
>var obj = db.person.findOne({index:6})
>db.person.find(obj,{comments:{$slice:2}})
>db.person.find(obj,{comments:{$slice:-2}})
> db.person.find(obj,{comments:{$slice:[1,2]}})
1.3数据库命令
>db.person.find()
> db.runCommand({find:'person'})
1.4 排序分页
排序使用这个sort函数进行
sort({key:1}) 按照key进行升序
sort({key:-1}) 按照key进行降序
limit(num) 限定结果只有num个元素
skip(num) 略过前num个元素
count({条件文档})进行个数查询
>db.person.find().sort({index:1})
如果我们的数据条数是11条
>var count = db.person.count()
我们分页,一页的数据条数是3条
那么我们可以分页的页数:
> count%3==0?count/3:Math.floor(count/3)+1
4
第一页的数据:
> db.person.find().limit(3).skip(0)
第二页的数据
> db.person.find().limit(3).skip(3)
第三页的数据
> db.person.find().limit(3).skip(6)
第四页的数据
> db.person.find().limit(3).skip(9)
所以如果我们的页数是page,每页数据的条数是num
那么第k 页的查询是
>
第三页的数据
> db.person.find().limit(page).skip((k-1)*page)
1.5 分组
group函数,它接受一个文档作为参数
有如下的属性:
key:表示按那些字段进行分组
例如 key:{kind:1} 1表示这个分组中的key要显示出来
initial:表示初始化的值
例如 initial:{person:[]}
$reduce: function(cur,prev)
如果接触过python就知道这个reduce函数了
它是一种合成的思想
用于操作复合的函数关系
把初始值给这个prev
然后将它和数组的第一项进行函数关系运算
得到的结果再和数组的第二项进行函数运算
如此下去。
condition:{条件过滤文档}
表示最后的分组中要过滤的条件
finalize:function(out)
表示分组完成之后每组必须进行的操作,这个out就是$reduce函数中的prev对象
这个group函数的操作就是先按照key进行分组
然后每一个分组都要按照 initial,conditon,$reduce,finalize来进行加工操作
最后输出的东西就是这个prev对象的属性和这个finalize函数中的out对象的属性
> db.person.group({
... key:{kind:1},
... initial:{person:[]},
... condition:{index:{$mod:[2,0]}},
... $reduce:function(cur,prev){
... prev.person.push(cur.index);
... }
... ,
... finalize:function(out){
... out.count = out.person.length;
... }
... }
... )