基础查询
MongoDB的查询操作非常重要,使用find和findOne进行查询,通过{}来设定查询条件,如果什么都不设置就是查询所有信息。
db.users.find() ##查询所有信息
db.users.findOne()##查询第一条记录
可以在find中使用逗号来分割多个查询条件,相当于关系数据库中的and操作
db.users.find({age:33})##查询年龄等于23的用户
> db.users.findOne({name:"foo",age:33})##查询名字为foo并且年龄为33的用户
{
"_id" : ObjectId("5a1971ff15143821a5de24c7"),
"name" : "foo",
"age" : 33,
"email" : "foo@example.com",
"gender" : "male"
}
我们可以通过find的第二个条件来指定显示哪些key的信息
> db.users.findOne({name:"foo",age:33},{email:1,name:1})##仅仅显示email和name的信息
{
"_id" : ObjectId("5a1971ff15143821a5de24c7"),
"name" : "foo",
"email" : "foo@example.com"
}
通过实例可以发现不管怎么设定都会显示_id,同样我们可以通过第二参数把key设置为0不显示信息
> db.users.findOne({name:"foo",age:33},{email:0})##排除email其他都显示
{
"_id" : ObjectId("5a1971ff15143821a5de24c7"),
"name" : "foo",
"age" : 33,
"gender" : "male"
}
>
通过下面的例子可以排除_id
> db.users.findOne({name:"foo",age:33},{_id:0,name:1})##仅仅显示name的信息
{ "name" : "foo" }
>
条件查询
MongoDB的查询同样可以像关系数据库一样加入>,<,=,!=的这些条件查询,只是使用的方式有些不一样而已
db.users.find({"age":{"$gte":20,"$lt":33}}).pretty() ##查询年龄大于等于20并且小于33的人
{
"_id" : ObjectId("5a19740415143821a5de24c8"),
"name" : "bar",
"age" : 23,
"email" : "bar@example.com",
"gender" : "male"
}
{
"_id" : ObjectId("5a19742115143821a5de24ca"),
"name" : "world",
"age" : 31,
"email" : "world@example.com",
"gender" : "male"
}
对于日期的处理也基本类似,使用new Date("yyyy-mm-dd")可以创建一个日期(详细日期:<YYYY-mm-ddTHH:MM:ss>),使用Date()可以插入当前日期。
##插入一条数据,日期是2017-12-22使用new Date()指定日期,使用Date()指定当前日期
> db.posts.insertOne({title:"first",content:".....",author:"foo",create:new Date("2017-12-22")})
> var d = new Date("2017-09-30")##创建一个日期对象
> db.posts.find({"create":{"$gt":d}}).pretty()##查询满足条件的日期对象
{
"_id" : ObjectId("5a1977a815143821a5de24d3"),
"title" : "first",
"content" : ".....",
"author" : "foo",
"create" : ISODate("2017-12-22T00:00:00Z")
}
使用ne表示查询不等于某个的值
> db.users.find({name:{$ne:"foo"}},{name:1}).pretty()##查询name不等于foo的所有users
{ "_id" : ObjectId("5a19740415143821a5de24c8"), "name" : "bar" }
{ "_id" : ObjectId("5a19741115143821a5de24c9"), "name" : "hello" }
{ "_id" : ObjectId("5a19742115143821a5de24ca"), "name" : "world" }
使用逗号分割查询是以AND来进行条件的合并,如果要进行OR的查询,MongoDB提供了in和or两种方式,in表示查询的内容在某个范围内,in表示在某个范围内,而nin表示在不在范围内
db.users.find({name:{$in:["foo","bar"]}},{_id:0})##name在某个范围内
{ "name" : "foo", "age" : 33, "email" : "foo@example.com", "gender" : "male" }
{ "name" : "bar", "age" : 23, "email" : "bar@example.com", "gender" : "male" }
> db.users.find({name:{$nin:["foo","bar"]}},{_id:0})##name不在某个范围内
{ "name" : "hello", "age" : 25, "email" : "hello@example.com", "gender" : "male" }
{ "name" : "world", "age" : 31, "email" : "world@example.com", "gender" : "male" }
or的使用方式也类似,下例展示了如何查询AND和OR
> db.users.find(
{age:{$gt:22},
$or:[{name:"foo"},{email:"hello@example.com"}] },
{_id:0}
)##查询,年龄大于22并且name为foo或者email为hello@example.com的所有users
{ "name" : "foo", "age" : 33, "email" : "foo@example.com", "gender" : "male" }
{ "name" : "hello", "age" : 25, "email" : "hello@example.com", "gender" : "male" }
特定类型的查询
首先看一下如何查询null的值,在MongoDB中null的值和关系数据库不太一样,关系数据库中,由于schema是固定的一般只会查询某个值为null,但是在MongoDB中可能存在没有这个Document的值,所以就会存在不同的需求。数据模型如下
> db.c.find()
{ "_id" : ObjectId("5a1b7bab29b9c4cdcc29a639"), "y" : 1 }
{ "_id" : ObjectId("5a1b7bad29b9c4cdcc29a63a"), "y" : 2 }
{ "_id" : ObjectId("5a1b7bb029b9c4cdcc29a63b"), "y" : null }
{ "_id" : ObjectId("5a1b7bb729b9c4cdcc29a63c"), "x" : 1 }
{ "_id" : ObjectId("5a1b7bb929b9c4cdcc29a63d"), "x" : 2 }
首先使用null来进行查询
> db.c.find({y:null})
{ "_id" : ObjectId("5a1b7bb029b9c4cdcc29a63b"), "y" : null }
{ "_id" : ObjectId("5a1b7bb729b9c4cdcc29a63c"), "x" : 1 }
{ "_id" : ObjectId("5a1b7bb929b9c4cdcc29a63d"), "x" : 2 }
我们发现查询出来的结果不仅仅包含了null值,还包含了不存在的值,此时如果希望查询是否包含需要使用exists来操作,需要强调的是exists是在查询的结果中过滤,所以并不是一个具体的条件,所以需要使用eq来配合。
db.c.find({y:{$eq:null,$exists:true}})##查询包含了y元素的并且y为null的
{ "_id" : ObjectId("5a1b7bb029b9c4cdcc29a63b"), "y" : null }
> db.c.find({y:{$eq:null,$exists:false}})##查询了不包含y元素的
{ "_id" : ObjectId("5a1b7bb729b9c4cdcc29a63c"), "x" : 1 }
{ "_id" : ObjectId("5a1b7bb929b9c4cdcc29a63d"), "x" : 2 }
MongoDB提供了正则表达式的查询,使用正则表达式可以组合出各种不同需求的查询,需要注意的是正则表达式的值使用/ 作为开始的和结束,如果要忽略大小写同样可以使用/i结尾,另外正则表达式的值不用加引号。
db.users.find({name:/^f+/},{name:1,_id:0})##通过正则表达式匹配name是以f开头的
{ "name" : "foo" }
{ "name" : "fok" }
正则表达式和not配合起来就更加的好用
> db.users.find({name:{$not:/f+/}},{name:1,_id:0})##匹配不存在f的所有值
{ "name" : "bar" }
{ "name" : "hello" }
{ "name" : "world" }
数组查询
匹配数组非常简单
> db.food.find({fruit:"apple"})))##此时会匹配包含apple的数组
{ "_id" : ObjectId("5a1c2a6929b9c4cdcc29a640"), "fruit" : [ "apple", "banana", "orange" ] }
{ "_id" : ObjectId("5a1c2b4f29b9c4cdcc29a641"), "fruit" : [ "apple", "peach", "orange" ] }
db.food.find({fruit:"apple"})))
这个会匹配所有包含了apple的数组,如果希望进行数组匹配使用all修饰符
>db.food.find({fruit:{$all:["apple","peach"]}},{_id:0})##匹配数组中包含有apple和peach的数据
{ "fruit" : [ "apple", "peach", "orange" ] }
以上匹配中apple和peach的顺序不会影响结果,通过下面的例子可以进行精确匹配,这个就连顺序也必须一样
db.food.find({fruit:["apple","peach","orange"]},{_id:0})##精确匹配,顺序要一致
{ "fruit" : [ "apple", "peach", "orange" ] }
> db.food.find({fruit:["apple","orange","peach"]},{_id:0})##顺序不一样无法找到数据
还可以指定位置来进行查询,如果要使用这种方式,需要注意的是key这个值必须加上"",下标是从0开始的
>db.food.find({"fruit.2":"orange"},{_id:0})##查询第三个元素是orange的数据
{ "fruit" : [ "apple", "banana", "orange" ] }
{ "fruit" : [ "apple", "peach", "orange" ] }
通过size可以查询数组长度等于某个值的数据,但是无法使用gt或者lt
> db.food.find({fruit:{$size:3}},{_id:0})##查询等于3的数据
{ "fruit" : [ "apple", "banana", "orange" ] }
{ "fruit" : [ "apple", "peach", "orange" ] }
> db.food.find({fruit:{$size:{$gte:3}}},{_id:0})##$size无法使用gt之类的条件
Error: error: {
如果希望做上面的操作,可以考虑插入一个size来保存,这个操作对性能的影响微乎其微,只是在插入数据的时候通过inc增加一条即可。对于find的第二个参数而言,如果时候数组可以通过slice来返回访问第几个元素
>db.food.find({fruit:"apple"},{fruit:{$slice:2},_id:0})##访问数组的前两个元素
{ "fruit" : [ "apple", "banana" ], "size" : 1 }
{ "fruit" : [ "apple", "peach" ] }
> db.food.find({fruit:"apple"},{fruit:{$slice:-2},_id:0})##访问后两个元素
{ "fruit" : [ "orange", "berry" ], "size" : 1 }
{ "fruit" : [ "peach", "orange" ] }
> db.food.find({fruit:"apple"},{fruit:{$slice:[2,3]},_id:0})##从第三个开始访问后三个元素
{ "fruit" : [ "orange", "berry" ], "size" : 1 }
{ "fruit" : [ "orange" ] }
下面将来演示几种内嵌文档的查询,首先看一下数据模型
> db.blog.findOne()
{
"_id" : ObjectId("5a1c339b29b9c4cdcc29a642"),
"title" : "first",
"content" : "...",
"author" : {
"name" : "leon",
"age" : 32
},
"comments" : [
{
"content" : "c1",
"author" : "joe",
"score" : 4
},
{
"content" : "c2",
"author" : "jake",
"score" : 6
}
]
}
要查询作者为leon的文档非常简单,通过.可以引导到关联对象中
> db.blog.find({"author.name":"leon"},{title:1,author:1,_id:0})
{ "title" : "first", "author" : { "name" : "leon", "age" : 32 } }
如果要查询
comments中作者为joe并且score大于等于5分的文章,这个需求如果按照常规的方式会把两条comments都查询出来,因为第二条comments的分数满足要求
> db.blog.find({"comments.author":"joe","comments.score":{$gte:5}},{title:1,author:1,_id:0})
{ "title" : "first", "author" : { "name" : "leon", "age" : 32 } }
这种情况需要使用elemMatch来解决
db.blog.find({"comments":{$elemMatch:{"author":"joe","score":{$gte:5}}}})
最后,还有一种where查询,这种查询的效率稍微有些低,但是基本可以实现所有的查询,它的查询思路是将BSON转换为javascript对象来处理,还是首先看看数据模型
> db.point.find({},{_id:0})
{ "x" : 10, "y" : 30 }
{ "x" : 20, "y" : 20 }
{ "x" : 60, "y" : 60 }
如果希望查询x+y的值为40的数据,使用普通的方式就不太好查询,此时可以通过where来完成,使用where之后可以通过this来引用对象
db.point.find(
... {$where:
... "function()
... {
... if(this.x+this.y==40)
... return true;
... else
... return false}
... "
... }) ##基于where的查询
{ "_id" : ObjectId("5a1c366429b9c4cdcc29a643"), "x" : 10, "y" : 30 }
{ "_id" : ObjectId("5a1c366b29b9c4cdcc29a644"), "x" : 20, "y" : 20 }
可以对上述的查询进行简单的转换,将function这些省略,只要写结果就行
> db.point.find({$where:"this.x+this.y==40"})
{ "_id" : ObjectId("5a1c366429b9c4cdcc29a643"), "x" : 10, "y" : 30 }
{ "_id" : ObjectId("5a1c366b29b9c4cdcc29a644"), "x" : 20, "y" : 20 }
最后再强调一下:where查询效率不高,一般非逼不得已不使用这个查询。
这一部分就讲这么多,通过这几部分的内容,基本对MongoDB有了一些基本的认识.