MongoDB学习系列 -- 文档查询

查询占了MongoDB的绝大多数操作,鉴于查询如此重要,我们单独拎出来学习一下。

其实,在之前的文章中,我们对于查询已经有了一部分接触,比如find(cond)、findOne(cond)。但是我们用到的只是一小部分,这节我们来详细学习一下。

一、查询条件

前面我们用到的查询都是精准匹配,而实际中我们可能还需要更复杂的查询条件,比如or、in、between、not in、>、>=、<、<=等。关于这些条件我就不需要多说了,大家应该也都可以理解,还是老规矩,show me the code!

db.student.find()
{ "_id" : ObjectId("5b3f782598781e88f5e3462f"), "name" : "xiaoming", "sex" : 1, "age" : 2 }
{ "_id" : ObjectId("5b401a87d3c72e6c8d190cf7"), "date" : ISODate("2018-07-07T01:42:31.010Z") }
{ "_id" : ObjectId("5b40d1ea5c99dd00d4d1585a"), "name" : "lucy", "age" : 1 }
{ "_id" : ObjectId("5b40d2275c99dd00d4d1585b"), "name" : "wangwu", "age" : 1 }
{ "_id" : ObjectId("5b3f79a5d16c252df9d143fc"), "age" : 31, "name" : "lily", "sex" : 1, "address" : "bj", "comment" : [ { "name" : "test2", "count" : 1 } ] }
> db.student.find({'age':{$lt:2}});  //age < 2 
{ "_id" : ObjectId("5b40d1ea5c99dd00d4d1585a"), "name" : "lucy", "age" : 1 }
{ "_id" : ObjectId("5b40d2275c99dd00d4d1585b"), "name" : "wangwu", "age" : 1 }
> db.student.find({'age':{$gt:1}}); //age>1
{ "_id" : ObjectId("5b3f782598781e88f5e3462f"), "name" : "xiaoming", "sex" : 1, "age" : 2 }
{ "_id" : ObjectId("5b3f79a5d16c252df9d143fc"), "age" : 31, "name" : "lily", "sex" : 1, "address" : "bj", "comment" : [ { "name" : "test2", "count" : 1 } ] }
> db.student.find({'age':{$gte:1,$lte:2}}); //1<age<2
{ "_id" : ObjectId("5b3f782598781e88f5e3462f"), "name" : "xiaoming", "sex" : 1, "age" : 2 }
{ "_id" : ObjectId("5b40d1ea5c99dd00d4d1585a"), "name" : "lucy", "age" : 1 }
{ "_id" : ObjectId("5b40d2275c99dd00d4d1585b"), "name" : "wangwu", "age" : 1 }
> db.student.find({'name':{$ne:'lily'}}); //name!='lily'
{ "_id" : ObjectId("5b3f782598781e88f5e3462f"), "name" : "xiaoming", "sex" : 1, "age" : 2 }
{ "_id" : ObjectId("5b401a87d3c72e6c8d190cf7"), "date" : ISODate("2018-07-07T01:42:31.010Z") }
{ "_id" : ObjectId("5b40d1ea5c99dd00d4d1585a"), "name" : "lucy", "age" : 1 }
{ "_id" : ObjectId("5b40d2275c99dd00d4d1585b"), "name" : "wangwu", "age" : 1 }
> db.student.find({'name':{$or:{'lily','xiaoming'}}}); //name='lily' || name ='xiaoming'
> db.student.find({'name':{$in:['lily','xiaoming']}});//name='lily' || name = 'xiaoming'
{ "_id" : ObjectId("5b3f782598781e88f5e3462f"), "name" : "xiaoming", "sex" : 1, "age" : 2 }
{ "_id" : ObjectId("5b3f79a5d16c252df9d143fc"), "age" : 31, "name" : "lily", "sex" : 1, "address" : "bj", "comment" : [ { "name" : "test2", "count" : 1 } ] }
> db.student.find({'name':{$not:{$in:['lily','xiaoming']}}},{'age':1,'sex':1}) //name!='lily' && name!='xiaoming'
{ "_id" : ObjectId("5b401a87d3c72e6c8d190cf7") }
{ "_id" : ObjectId("5b40d1ea5c99dd00d4d1585a"), "age" : 1 }
{ "_id" : ObjectId("5b40d2275c99dd00d4d1585b"), "age" : 1 }

二、特定类型的查询

我们知道MongoDB有一种数据类型为null,null比较特殊,不仅会匹配自身,还会匹配不存在的,会返回缺少这个键的所有文档。比较特殊,要特别注意。

db.student.find({'class':null})
{ "_id" : ObjectId("5b3f782598781e88f5e3462f"), "name" : "xiaoming", "sex" : 1, "age" : 2 }
{ "_id" : ObjectId("5b401a87d3c72e6c8d190cf7"), "date" : ISODate("2018-07-07T01:42:31.010Z") }
{ "_id" : ObjectId("5b40d1ea5c99dd00d4d1585a"), "name" : "lucy", "age" : 1 }
{ "_id" : ObjectId("5b40d2275c99dd00d4d1585b"), "name" : "wangwu", "age" : 1 }
{ "_id" : ObjectId("5b3f79a5d16c252df9d143fc"), "age" : 31, "name" : "lily", "sex" : 1, "address" : "bj", "comment" : [ { "name" : "test2", "count" : 1 } ] }
{ "_id" : ObjectId("5b41c2b7a1cdee4710eeb247"), "name" : "lily", "class" : null }

三、模糊查询

说到查询,大家可能还会想到,支不支持正则表达式的查询呢?答案是肯定的,不得不说,MongoDB做的很人性化,MongoDB使用Perl兼容的正则表达式来匹配正则表达式。

下面来实践一把,查询以'y'结尾的name。

db.student.find({'name':/y$/i})
{ "_id" : ObjectId("5b40d1ea5c99dd00d4d1585a"), "name" : "lucy", "age" : 1 }
{ "_id" : ObjectId("5b3f79a5d16c252df9d143fc"), "age" : 31, "name" : "lily", "sex" : 1, "address" : "bj", "comment" : [ { "name" : "test2", "count" : 1 } ] }
{ "_id" : ObjectId("5b41c2b7a1cdee4710eeb247"), "name" : "lily", "class" : null }

四、$where查询

键值对是很好的查询方式,但是依然有些需求是它无法表达的。这个时候就需要使用$where字句了,可以使用它执行任何javascript作为查询的一部分,这就使得查询能够做几乎任何事情。但是,不是非常必要时,尽量不要使用它。这是因为他在速度上要比常规查询慢很多。每个文档都要从BSON转换为javascript对象,然后通过$where的表达式来运行。同样的是还不能使用索引。关于这部分的使用这里不再展开,具体可以查询其他的文档。

五、筛选查询结果

实际查询时,我们可能只关注文档的一部分数据,建议按需所取。这样不仅可以减少网络传输量,还可以减轻客户端数据解包的难度、提升性能。

find()的第二个参数表示筛选的字段,默认是返回满足筛选条件的所有信息。为某个字段设置为1表示返回,为0表示不返回。0和1不可以结合使用。_id是默认返回的,就算你没有显示的设置。

> db.student.findOne({'name':'lily'},{'age':1,'sex':1})
{ "_id" : ObjectId("5b3f79a5d16c252df9d143fc"), "age" : 31, "sex" : 1 }
> db.student.findOne({'name':'lily'},{'sex':0})
{
        "_id" : ObjectId("5b3f79a5d16c252df9d143fc"),
        "age" : 31,
        "name" : "lily",
        "address" : "bj",
        "comment" : [
                {
                        "name" : "test2",
                        "count" : 1
                }
        ]
}

六、筛选查询数量

更多时候我们需要限制返回结果的数量,忽略一定数量的结果并进行排序。所有的这些选项都要在查询被派发到服务器之前添加。主要有三个函数limit()、sort()、skip()。三者的使用相信大家有在其他语言中接触过,不再详细展开了。

sort会用一个对象作为参数:一组键值对,键对应文档的键名,值代表排序的方向。排序方向可以是1(升序)或者-1(降序),如果指定了多个键,则按照多个键的顺序逐个排序。

三个函数可以组合使用,主要应用场景是分页。下面举例来说明。

按照sex降序排列,skip一个文档,选择两个。

db.student.find()
{ "_id" : ObjectId("5b3f782598781e88f5e3462f"), "name" : "xiaoming", "sex" : 1, "age" : 2 }
{ "_id" : ObjectId("5b401a87d3c72e6c8d190cf7"), "date" : ISODate("2018-07-07T01:42:31.010Z") }
{ "_id" : ObjectId("5b40d1ea5c99dd00d4d1585a"), "name" : "lucy", "age" : 1 }
{ "_id" : ObjectId("5b40d2275c99dd00d4d1585b"), "name" : "wangwu", "age" : 1 }
{ "_id" : ObjectId("5b3f79a5d16c252df9d143fc"), "age" : 31, "name" : "lily", "sex" : 1, "address" : "bj", "comment" : [ { "name" : "test2", "count" : 1 } ] }
{ "_id" : ObjectId("5b41c2b7a1cdee4710eeb247"), "name" : "lily", "class" : null }
> db.student.find().sort({'age':-1}).skip(1).limit(2)
{ "_id" : ObjectId("5b3f782598781e88f5e3462f"), "name" : "xiaoming", "sex" : 1, "age" : 2 }
{ "_id" : ObjectId("5b40d1ea5c99dd00d4d1585a"), "name" : "lucy", "age" : 1 }

注:大家知道MongoDB的数据类型是多样的,一个key可能是多个数据类型。一上面的例子为例,如果有些文档的sex不是整形,而是字符串或者布尔类型,这个时候我们再以上面的方式执行查询的时候会出现什么效果呢?

大家可以实践一下,这个问题下一篇文章会介绍。

MongoDB学习系列 -- 基础知识了解

MongoDB学习系列 -- 常见的限制

MongoDB学习系列 -- 数据库、集合、文档的CURD

MongoDB学习系列 -- 数组修改器

猜你喜欢

转载自blog.csdn.net/ydm19891101/article/details/80959503
今日推荐