赞
踩
目录
最简单的查询表达式 {filed:value} ,是指查询field列的值为value的文档。
首先导入测试数据:https://github.com/rxbook/mongodb_test/blob/master/test1.json
例:查询主键为32的商品:
- db.goods.find({goods_id:32});
- MySQL中:select * from goods where goods_id=32
用法:{field:{$ne:value}} ,查找filed列的值 不等于 value 的文档
例2:cat_id不等于3的相关记录
- db.goods.find({cat_id:{$ne:3}},{goods_id:1,cat_id:1,goods_name:1,_id:0});
- MySQL中: select field from goods where cat_id!=3
用法:{field:{$gt:value}} ,查找filed列的值 大于 value 的文档
例3: shop_price大于3的相关记录
- db.goods.find({shop_price:{$gt:3}},{goods_id:1,goods_name:1,shop_price:1,_id:0});
- MySQL中: select field from goods where shop_price>3
例: shop_price小于或等于100元的商品($lte)
- db.goods.find({shop_price:{$lte:100}},{goods_name:1,shop_price:1});
- MySQL中:select field from goods where shop_price<=3000
例:取出cat_id=4或cat_id=11的商品($in)
- db.goods.find({cat_id:{$in:[4,11]}},{cat_id:1,goods_name:1});
- MySQL中: select field from goods where cat_id IN (4,11)
语法: {field:{$all:[v1,v2..]}} ,是指取出 field列是一个数组,且至少包含 v1,v2值。MySQL中没有此用法。
例:取出emp表中,hobby字段包含“A”和“B”的:
db.emp.find({hobby:{$all:[‘A’,’B’]}});
例:取出价格介于100到500之间的商品($and)
- db.goods.find({
- $and:[
- {shop_price:{$gt:100}},
- {shop_price:{$lt:500}}
- ]} , {
- goods_name:1,
- shop_price:1,
- _id:0
- });
-
- MySQL中:where price>=100 AND price<=500 或 where price BETWEEN 100 AND 500
分析:
- {shop_price:{$gte:100}} -- A
- {shop_price:{$lte:500}} -- B
- {$and:[A,B]},{goods_name:1,shop_price:1,_id:0}
例:取出(价格大于40且小于100),或者(大于1000且小于2000)的商品($or)
这样写效率比较高,但是有点复杂,可以通过$where的方式写,比较简单,同时效率较低。参照后面的$where部分。
- db.goods.find({$or:[
- {$and:[{shop_price:{$gt:40}},{shop_price:{$lt:100}}]},
- {$and:[{shop_price:{$gt:1000}},{shop_price:{$lt:2000}}]}
- ]},{goods_name:1,shop_price:1,_id:0});
-
- MySQL中: where (price>40 AND price<100) OR (price>1000 AND price<2000)
例:取出cat_id不等于3,并且cat_id不等于11的商品($and 、 $nin 、 $nor分别实现)
db.goods.find({$and:[{cat_id:{$ne:3}},{cat_id:{$ne:11}}]},{goods_name:1,cat_id:1})
db.goods.find({cat_id:{$nin:[3,11]}},{goods_name:1,cat_id:1});
{$nor,[条件1,条件2]} —— (既不是...,也不是...),所有列举条件都不成功则为真,其实就是和$and互逆的运算符。
db.goods.find({$nor:[{cat_id:3},{cat_id:11}]},{goods_name:1,cat_id:1});
例: 取出{goods_id%5 == 1} , 即goods_id等于1,6,11,..这样的商品 [MySQL中没有此功能]
db.goods.find({goods_id:{$mod:[5,1]}},{goods_id:1,goods_name:1,_id:0});
查询出含有field字段的文档,存在即可被查找出来。
例:取出有age属性的文档 [MySQL中没有此功能,因为MySQL每一条数据对应的列是固定的 ]
db.stu.find({age:{$exists:1}}); #含有age属性的文档将会被查出
查询出含有field字段的类型为2的。
例:取出name字段是字符串类型的 [MySQL中没有此功能,因为MySQL每一列的类型都是固定的,例如varchar、int ]
db.foo.find({age:{$type:2}}); #name字段属于字符串类型的将会被查出
同样的,要查出数值类型的(Double),使用如下:
$where效率较低,因为要把二进制转换成js引擎后再进行查询,所以一般情况下不建议这样查询。
例: db.goods.find({$where:'this.cat_id != 3 && this.cat_id != 11'});
db.goods.find({$where:'this.shop_price>5000'});
例:取出(价格大于40且小于100),或者(大于1000且小于2000)的商品,上面用 $or 实现了,这里用$where 试一下。当然,简单了一些,效率也较低。
- db.goods.find({
- $where: '(this.shop_price>40 && this.shop_price<100) || (this.shop_price>1000 && this.shop_price<2000)'
- },{
- goods_name:1,
- shop_price:1,
- _id:0
- });
注意: 用$where查询时, mongodb是把bson结构的二进制数据转换为json结构的对象, 然后比较对象的属性是否满足表达式,因此速度较慢!
用正则表达式查询 以”诺基亚”开头的商品,这样查询效率也比较低。
db.goods.find({goods_name:{$regex:/^诺基亚*/}},{goods_id:1,goods_name:1,_id:0});
- 1:主键为32的商品
- db.goods.find({goods_id:32});
-
- 2:不属第3栏目的所有商品($ne)
- db.goods.find({cat_id:{$ne:3}},{goods_id:1,cat_id:1,goods_name:1});
-
- 3:本店价格高于3000元的商品{$gt}
- db.goods.find({shop_price:{$gt:3000}},{goods_name:1,shop_price:1});
-
- 4:本店价格低于或等于100元的商品($lte)
- db.goods.find({shop_price:{$lte:100}},{goods_name:1,shop_price:1});
-
- 5:取出第4栏目或第11栏目的商品($in)
- db.goods.find({cat_id:{$in:[4,11]}},{goods_name:1,shop_price:1});
-
- 6:取出100<=价格<=500的商品($and)
- db.goods.find({$and:[{price:{$gt:100},{$price:{$lt:500}}}]);
-
- 7:取出不属于第3栏目且不属于第11栏目的商品($and $nin和$nor分别实现)
- db.goods.find({$and:[{cat_id:{$ne:3}},{cat_id:{$ne:11}}]},{goods_name:1,cat_id:1})
- db.goods.find({cat_id:{$nin:[3,11]}},{goods_name:1,cat_id:1});
- db.goods.find({$nor:[{cat_id:3},{cat_id:11}]},{goods_name:1,cat_id:1});
-
- 8:取出价格大于100且小于300,或者大于4000且小于5000的商品()
- db.goods.find({$or:[{$and:[{shop_price:{$gt:100}},{shop_price:{$lt:300}}]},{$and:[{shop_price:{$gt:4000}},{shop_price:{$lt:5000}}]}]},{goods_name:1,shop_price:1});
-
- 9:取出goods_id%5 == 1, 即,1,6,11,..这样的商品
- db.goods.find({goods_id:{$mod:[5,1]}});
-
- 10:取出有age属性的文档
- db.stu.find({age:{$exists:1}});
- # 含有age属性的文档将会被查出
准备工作:给stu文档中插入1000条数据:
查询sn:99的用户:
可以使用 db.find(query).explain(); 查看查询计划,类似于MySQL的explain解析。
db.stu.find({sn:99}).explain();
- "cursor" : "BasicCursor", ----说明没有索引发挥作用
- "nscannedObjects" : 1000 ----理论上要扫描多少行:1000行
关于索引的说明:
db.collection.ensureIndex({field:1/-1}); #1是升续,2是降续。
db.stu.ensureIndex({sn:1});
然后再explain查看就不一样了:
- "cursor" : "BtreeCursor sn_1" ----用到的btree索引
- "nscannedObjects" : 1 ----只需要扫描1行即可
db.collection.getIndexes();
db.stu.getIndexes();
可以看到,_id是默认的必须有的索引!
必须指定是1还是-1:db.collection.dropIndex({filed:1/-1});
db.stu.dropIndex({sn:1});
db.collection.dropIndexes();
db.stu.dropIndexes();
删除所有索引之后,_id还在,说明 _id是必须存在的索引!
db.collection.ensureIndex({field1:1/-1, field2:1/-1});
db.stu.ensureIndex({sn:1,name:1});
注意:两个列一起加索引 和 给两个列分别加索引是不一样的,多列索引是两个列绑定在一起作为索引的。
此例中,一般用于 sn 和 name 放在一起查询次数较多的情况下使用。
db.collection.ensureIndex({filed.subfield:1/-1});
① 首先插入两条包含子文档的数据:
② 现在需要查询 area 属性值是’taiwan’的记录,就是 查询子文档,需要使用: db.collectionName.find({filed.subfield:1/-1});
db.shop.find({'spc.area':'taiwan'});
③ 给子文档 area 添加索引,和查询的方法很类似:
db.shop.ensureIndex({'spc.area':1});
db.collection.ensureIndex({filed.subfield:1/-1}, {unique:true});
① [准备工作] 给 tea 文档添加两条数据:
② [创建唯一索引命令]
db.tea.ensureIndex({email:1},{unique:true});
③ 现在测试,插入两条同样的记录,就会报错:
[准备工作] 插入一条空的信息 {} ,然后给email列添加普通索引,再查询 {email:null} 和 explain的结果:
- db.tea.insert({});
- db.tea.ensureIndex({email:1});
- db.tea.find({email:null});
- db.tea.find({email:null}).explain();
稀疏索引 :如果针对field做索引,针对不含field列的文档,将不建立索引.与之相对,普通索引,会把该文档的field列的值认为NULL,并建索引.适宜于:小部分文档含有某列时. db.collection.ensureIndex({field:1/-1},{sparse:true});
接下来,删除所有已有的索引,然后添加稀疏索引,继续上面的查询 {email:null},就查不到结果了。
db.tea.ensureIndex({email:1},{sparse:true});
稀疏索引使用情景总结:
- > db.tea.find();
- { "_id" : ObjectId("5275f99b87437c610023597b"), "email" : "a@163.com" }
- { "_id" : ObjectId("5275f99e87437c610023597c"), "email" : "b@163.com" }
- { "_id" : ObjectId("5275f9e887437c610023597e"), "email" : "c@163.com" }
- { "_id" : ObjectId("5275fa3887437c6100235980") }
如上内容,最后一行没有email列,如果分别加普通索引,和稀疏索引,对于最后一行的email分别当成null(普通索引) 和 忽略最后一行(稀疏索引) 来处理。根据{email:null}来查询,前者(普通索引)能查到,而后者(稀疏索引)查不到最后一行.
哈希索引速度比普通索引快,但是,无能对范围查询进行优化.适宜于---随机性强的散列
语法: db.collection.ensureIndex({file:’hashed’});
db.tea.ensureIndex({email:'hashed'});
一个表经过很多次修改后,导致表的文件产生空洞,索引文件也如此.可以通过索引的重建,减少索引文件碎片,并提高索引的效率.类似mysql中的optimize table
语法: db.collection.reIndex();
通俗的说,游标不是查询结果,而是查询的返回资源,或者接口.通过这个接口,你可以逐条读取.就像php中的fopen打开文件,得到一个资源一样, 通过资源,可以一行一行的读文件.
测试:在Mongodb中一次性插入10000条数据:
- for(var i=0;i<10000;i++){
- db.bar.insert({_id:i+1,title:'hello world'+i,content:'aaa'+i});
- };
声明游标:
- var mycursor = db.collectioName.find(query,projection);
- mycursor.hasNext() //判断游标是否已经取到尽头
- mycursor.Next() //取出游标的下1个单元
-
- [完整代码,只取前5条作为演示]
- var mycursor = db.bar.find({_id:{$lte:5}});
- print(mycursor.next()); //取出的是bson对象的格式,需要使用printjson打印
- printjson(mycursor.next()); //取出的是json格式
用while循环来打印游标,避免一个一个的手动操作。
- var mycursorr = db.bar.find({_id:{$lte:5}});
- while(mycursorr.hasNext()) {
- printjson(mycursorr.next());
- }
用for循环来打印游标,更简单。
- for(var cursor=db.bar.find({_id:{$lte:5}});cursor.hasNext();) {
- printjson(cursor.next());
- }
游标的迭代函数forEach,允许我们自定义回调函数来逐个处理每个单元.
cursor.forEach(回调函数);
- var mycursor = db.bar.find({_id:{$lte:5}});
- mycursor.forEach(function(obj){
- printjson(obj)
- });
【扩展】function(obj){...} 这里不光可以print json,还可以进行编程处理,如下:
- var mycursor = db.bar.find({_id:{$lte:5}});
- mycursor.forEach(function(obj){
- print('your id is:'+obj._id+',your content is:'+obj.content)
- });
游标在分页中的应用
比如查到10000行,跳过100页,取10行.一般地,我们假设每页N行, 当前是page页,就需要跳过前 (page-1)*N 行, 再取N行, 在mysql中, limit (offset,N) 来实现。在mongo中,用skip(), limit() 函数来实现的
var mycursor = db.bar.find().skip(9995); 则是查询结果中,跳过前9995行
- var mycursor = db.bar.find().skip(9995);
- mycursor.forEach(function(obj){printjson(obj)});
var mycursor = db.bar.find().skip(9000).limit(10); 则是查询第901页,每页10条;也就是从第9000条开始取10条数据。
- var mycursor = db.bar.find().skip(9000).limit(10);
- mycursor.forEach(function(obj){printjson(obj)});
不用游标也可以直接使用skip()和limit()来查询
db.bar.find().skip(9000).limit(10);
通过cursor一次性得到所有数据, 并返回数组.
- var cursor = db.bar.find().skip(9000).limit(5);
- printjson(cursor.toArray()); //看到所有行
- printjson(cursor.toArray()[2]); //看到第2行
注意: 不要随意使用toArray(),原因: 会把所有的行立即以对象形式组织在内存里.可以在取出少数几行时用此功能.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。