基礎(chǔ)查詢
MongoDB的查詢操作非常重要,使用find和findOne進(jìn)行查詢,通過(guò){}來(lái)設(shè)定查詢條件,如果什么都不設(shè)置就是查詢所有信息。
db.users.find() ##查詢所有信息
db.users.findOne()##查詢第一條記錄
可以在find中使用逗號(hào)來(lái)分割多個(gè)查詢條件,相當(dāng)于關(guān)系數(shù)據(jù)庫(kù)中的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"
}
我們可以通過(guò)find的第二個(gè)條件來(lái)指定顯示哪些key的信息
> db.users.findOne({name:"foo",age:33},{email:1,name:1})##僅僅顯示email和name的信息
{
"_id" : ObjectId("5a1971ff15143821a5de24c7"),
"name" : "foo",
"email" : "foo@example.com"
}
通過(guò)實(shí)例可以發(fā)現(xiàn)不管怎么設(shè)定都會(huì)顯示_id,同樣我們可以通過(guò)第二參數(shù)把key設(shè)置為0不顯示信息
> db.users.findOne({name:"foo",age:33},{email:0})##排除email其他都顯示
{
"_id" : ObjectId("5a1971ff15143821a5de24c7"),
"name" : "foo",
"age" : 33,
"gender" : "male"
}
>
通過(guò)下面的例子可以排除_id
> db.users.findOne({name:"foo",age:33},{_id:0,name:1})##僅僅顯示name的信息
{ "name" : "foo" }
>
條件查詢
MongoDB的查詢同樣可以像關(guān)系數(shù)據(jù)庫(kù)一樣加入>,<,=,!=的這些條件查詢,只是使用的方式有些不一樣而已
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"
}
對(duì)于日期的處理也基本類(lèi)似,使用new Date("yyyy-mm-dd")可以創(chuàng)建一個(gè)日期(詳細(xì)日期:<YYYY-mm-ddTHH:MM:ss>),使用Date()可以插入當(dāng)前日期。
##插入一條數(shù)據(jù),日期是2017-12-22使用new Date()指定日期,使用Date()指定當(dāng)前日期
> db.posts.insertOne({title:"first",content:".....",author:"foo",create:new Date("2017-12-22")})
> var d = new Date("2017-09-30")##創(chuàng)建一個(gè)日期對(duì)象
> db.posts.find({"create":{"$gt":d}}).pretty()##查詢滿足條件的日期對(duì)象
{
"_id" : ObjectId("5a1977a815143821a5de24d3"),
"title" : "first",
"content" : ".....",
"author" : "foo",
"create" : ISODate("2017-12-22T00:00:00Z")
}
使用ne表示查詢不等于某個(gè)的值
> 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" }
使用逗號(hào)分割查詢是以AND來(lái)進(jìn)行條件的合并,如果要進(jìn)行OR的查詢,MongoDB提供了in和or兩種方式,in表示查詢的內(nèi)容在某個(gè)范圍內(nèi),in表示在某個(gè)范圍內(nèi),而nin表示在不在范圍內(nèi)
db.users.find({name:{$in:["foo","bar"]}},{_id:0})##name在某個(gè)范圍內(nèi)
{ "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不在某個(gè)范圍內(nèi)
{ "name" : "hello", "age" : 25, "email" : "hello@example.com", "gender" : "male" }
{ "name" : "world", "age" : 31, "email" : "world@example.com", "gender" : "male" }
or的使用方式也類(lèi)似,下例展示了如何查詢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" }
特定類(lèi)型的查詢
首先看一下如何查詢null的值,在MongoDB中null的值和關(guān)系數(shù)據(jù)庫(kù)不太一樣,關(guān)系數(shù)據(jù)庫(kù)中,由于schema是固定的一般只會(huì)查詢某個(gè)值為null,但是在MongoDB中可能存在沒(méi)有這個(gè)Document的值,所以就會(huì)存在不同的需求。數(shù)據(jù)模型如下
> 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來(lái)進(jìn)行查詢
> db.c.find({y:null})
{ "_id" : ObjectId("5a1b7bb029b9c4cdcc29a63b"), "y" : null }
{ "_id" : ObjectId("5a1b7bb729b9c4cdcc29a63c"), "x" : 1 }
{ "_id" : ObjectId("5a1b7bb929b9c4cdcc29a63d"), "x" : 2 }
我們發(fā)現(xiàn)查詢出來(lái)的結(jié)果不僅僅包含了null值,還包含了不存在的值,此時(shí)如果希望查詢是否包含需要使用exists來(lái)操作,需要強(qiáng)調(diào)的是exists是在查詢的結(jié)果中過(guò)濾,所以并不是一個(gè)具體的條件,所以需要使用eq來(lái)配合。
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提供了正則表達(dá)式的查詢,使用正則表達(dá)式可以組合出各種不同需求的查詢,需要注意的是正則表達(dá)式的值使用/ 作為開(kāi)始的和結(jié)束,如果要忽略大小寫(xiě)同樣可以使用/i結(jié)尾,另外正則表達(dá)式的值不用加引號(hào)。
db.users.find({name:/^f+/},{name:1,_id:0})##通過(guò)正則表達(dá)式匹配name是以f開(kāi)頭的
{ "name" : "foo" }
{ "name" : "fok" }
正則表達(dá)式和not配合起來(lái)就更加的好用
> db.users.find({name:{$not:/f+/}},{name:1,_id:0})##匹配不存在f的所有值
{ "name" : "bar" }
{ "name" : "hello" }
{ "name" : "world" }
數(shù)組查詢
匹配數(shù)組非常簡(jiǎn)單
> db.food.find({fruit:"apple"})))##此時(shí)會(huì)匹配包含apple的數(shù)組
{ "_id" : ObjectId("5a1c2a6929b9c4cdcc29a640"), "fruit" : [ "apple", "banana", "orange" ] }
{ "_id" : ObjectId("5a1c2b4f29b9c4cdcc29a641"), "fruit" : [ "apple", "peach", "orange" ] }
db.food.find({fruit:"apple"}))) 這個(gè)會(huì)匹配所有包含了apple的數(shù)組,如果希望進(jìn)行數(shù)組匹配使用all修飾符
>db.food.find({fruit:{$all:["apple","peach"]}},{_id:0})##匹配數(shù)組中包含有apple和peach的數(shù)據(jù)
{ "fruit" : [ "apple", "peach", "orange" ] }
以上匹配中apple和peach的順序不會(huì)影響結(jié)果,通過(guò)下面的例子可以進(jìn)行精確匹配,這個(gè)就連順序也必須一樣
db.food.find({fruit:["apple","peach","orange"]},{_id:0})##精確匹配,順序要一致
{ "fruit" : [ "apple", "peach", "orange" ] }
> db.food.find({fruit:["apple","orange","peach"]},{_id:0})##順序不一樣無(wú)法找到數(shù)據(jù)
還可以指定位置來(lái)進(jìn)行查詢,如果要使用這種方式,需要注意的是key這個(gè)值必須加上"",下標(biāo)是從0開(kāi)始的
>db.food.find({"fruit.2":"orange"},{_id:0})##查詢第三個(gè)元素是orange的數(shù)據(jù)
{ "fruit" : [ "apple", "banana", "orange" ] }
{ "fruit" : [ "apple", "peach", "orange" ] }
通過(guò)size可以查詢數(shù)組長(zhǎng)度等于某個(gè)值的數(shù)據(jù),但是無(wú)法使用gt或者lt
> db.food.find({fruit:{$size:3}},{_id:0})##查詢等于3的數(shù)據(jù)
{ "fruit" : [ "apple", "banana", "orange" ] }
{ "fruit" : [ "apple", "peach", "orange" ] }
> db.food.find({fruit:{$size:{$gte:3}}},{_id:0})##$size無(wú)法使用gt之類(lèi)的條件
Error: error: {
如果希望做上面的操作,可以考慮插入一個(gè)size來(lái)保存,這個(gè)操作對(duì)性能的影響微乎其微,只是在插入數(shù)據(jù)的時(shí)候通過(guò)inc增加一條即可。對(duì)于find的第二個(gè)參數(shù)而言,如果時(shí)候數(shù)組可以通過(guò)slice來(lái)返回訪問(wèn)第幾個(gè)元素
>db.food.find({fruit:"apple"},{fruit:{$slice:2},_id:0})##訪問(wèn)數(shù)組的前兩個(gè)元素
{ "fruit" : [ "apple", "banana" ], "size" : 1 }
{ "fruit" : [ "apple", "peach" ] }
> db.food.find({fruit:"apple"},{fruit:{$slice:-2},_id:0})##訪問(wèn)后兩個(gè)元素
{ "fruit" : [ "orange", "berry" ], "size" : 1 }
{ "fruit" : [ "peach", "orange" ] }
> db.food.find({fruit:"apple"},{fruit:{$slice:[2,3]},_id:0})##從第三個(gè)開(kāi)始訪問(wèn)后三個(gè)元素
{ "fruit" : [ "orange", "berry" ], "size" : 1 }
{ "fruit" : [ "orange" ] }
下面將來(lái)演示幾種內(nèi)嵌文檔的查詢,首先看一下數(shù)據(jù)模型
> 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的文檔非常簡(jiǎn)單,通過(guò).可以引導(dǎo)到關(guān)聯(lián)對(duì)象中
> db.blog.find({"author.name":"leon"},{title:1,author:1,_id:0})
{ "title" : "first", "author" : { "name" : "leon", "age" : 32 } }
如果要查詢
comments中作者為joe并且score大于等于5分的文章,這個(gè)需求如果按照常規(guī)的方式會(huì)把兩條comments都查詢出來(lái),因?yàn)榈诙lcomments的分?jǐn)?shù)滿足要求
> db.blog.find({"comments.author":"joe","comments.score":{$gte:5}},{title:1,author:1,_id:0})
{ "title" : "first", "author" : { "name" : "leon", "age" : 32 } }
這種情況需要使用elemMatch來(lái)解決
db.blog.find({"comments":{$elemMatch:{"author":"joe","score":{$gte:5}}}})
最后,還有一種where查詢,這種查詢的效率稍微有些低,但是基本可以實(shí)現(xiàn)所有的查詢,它的查詢思路是將BSON轉(zhuǎn)換為javascript對(duì)象來(lái)處理,還是首先看看數(shù)據(jù)模型
> db.point.find({},{_id:0})
{ "x" : 10, "y" : 30 }
{ "x" : 20, "y" : 20 }
{ "x" : 60, "y" : 60 }
如果希望查詢x+y的值為40的數(shù)據(jù),使用普通的方式就不太好查詢,此時(shí)可以通過(guò)where來(lái)完成,使用where之后可以通過(guò)this來(lái)引用對(duì)象
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 }
可以對(duì)上述的查詢進(jìn)行簡(jiǎn)單的轉(zhuǎn)換,將function這些省略,只要寫(xiě)結(jié)果就行
> db.point.find({$where:"this.x+this.y==40"})
{ "_id" : ObjectId("5a1c366429b9c4cdcc29a643"), "x" : 10, "y" : 30 }
{ "_id" : ObjectId("5a1c366b29b9c4cdcc29a644"), "x" : 20, "y" : 20 }
最后再?gòu)?qiáng)調(diào)一下:where查詢效率不高,一般非逼不得已不使用這個(gè)查詢。
這一部分就講這么多,通過(guò)這幾部分的內(nèi)容,基本對(duì)MongoDB有了一些基本的認(rèn)識(shí).