1. 程式人生 > >Mongodb 3.0+操作手冊 純手打

Mongodb 3.0+操作手冊 純手打

許可權控制

使用者概念

Mongodb的使用者是由 使用者名稱+所屬庫名組成

例如:

登入mongo testdb1 ,建立使用者testuser

登入mongo testdb2 ,建立使用者testuser

那上面建立的使用者分別是:[email protected][email protected]

也就是說在哪個庫下面建立使用者,這個使用者就是哪個庫的

內建角色

Mongodb的授權採用了角色授權的方法,每個角色包括一組許可權。

Mongodb已經定義好了的角色叫內建角色,我們也可以自定義角色。

這兒主要介紹內建角色,Mongodb內建角色包括下面幾類:

1. 資料庫使用者角色:read、readWrite;

2. 資料庫管理角色:dbAdmin、dbOwner、userAdmin;

3. 叢集管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;

4. 備份恢復角色:backup、restore;

5. 所有資料庫角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase

6. 超級使用者角色:root

這裡還有幾個角色間接或直接提供了系統超級使用者的訪問(dbOwner 、userAdmin、userAdminAnyDatabase)

7. 內部角色:__system

角色許可權

資料庫管理角色:

read:該角色只有讀取資料的許可權。只需讀許可權可以備份資料庫

readWrite:該角色有資料的讀寫許可權,但不能建立刪除索引,也不能建立和刪除資料庫。讀寫許可權可以還原資料庫備份

dbAdmin:該角色擁有資料庫管理許可權(比如更改資料庫型別)

dbOwner:是read、readWrite、dbAdmin這三者角色的集合體

userAdmin:該角色可以對其他角色許可權進行管理

叢集管理角色:

clusterAdmin:提供了最大的叢集管理功能。相當於clusterManager,clusterMonitor,

and hostManager和dropDatabase的許可權組合

clusterManager:提供了叢集和複製集管理和監控操作。擁有該許可權的使用者可以操作config和local資料庫(即分片和複製功能)

clusterMonitor:僅僅監控叢集和複製集

hostManager:提供了監控和管理伺服器的許可權,包括shutdown節點,logrotate, repairDatabase等。

所有資料庫角色:

readAnyDatabase:具有read每一個數據庫許可權。但是不包括應用到叢集中的資料庫。

readWriteAnyDatabase:具有readWrite每一個數據庫許可權。但是不包括應用到叢集中的資料庫。

userAdminAnyDatabase:具有userAdmin每一個數據庫許可權,但是不包括應用到叢集中的資料庫。

dbAdminAnyDatabase:提供了dbAdmin每一個數據庫許可權,但是不包括應用到叢集中的資料庫。

超級管理員許可權:

root: dbadmin到admin資料庫、useradmin到admin資料庫以及UserAdminAnyDatabase。

但它不具有備份恢復、直接操作system.*集合的許可權,但是擁有root許可權的超級使用者

可以自己給自己賦予這些許可權。

1、找到mongodb配置檔案,設定noauth=true

重啟Mongodb後,登入admin賬號,建立一個超級許可權使用者

語法:

use admin

db.createUser({user:'root',pwd:'root',roles:[{ "role" : "root", "db" : "admin" }]});

2、關閉mongodb

3、啟用認證引數

要保證許可權認證生效,需要在mongodb配置檔案中加入auth=true,同時刪掉noauth=true

4、啟動Mongodb

5、認證登入

(1)在連線期間進行身份驗證:

mongo 127.0.0.1:27017/db -u username  -p  passwordxxx

(2)連線後驗證

切換到身份驗證資料庫(在這裡為test),並使用db.auth(<username>,<pwd>)方法進行身份驗證:

use test

db.auth("myTester", "xyz123" )

1、建立使用者並授權

語法:

db.createUser({user:"UserName",pwd:"Password",roles:[{role:"RoleName",db:"Target_DBName"}]})

首先選擇在哪個庫建立使用者,如test:use test;

建立使用者有3項需要提供:使用者名稱,密碼,角色列表

例如我要在test下面建立用testuser,密碼為testpwd,角色列表包括test庫的readWrite角色和userAdmin角色:

db.createUser({user:"testuser",pwd:"testpwd",roles:[{role:"readWrite",db:"test"},{role:"userAdmin",db:"test"}]})

使用者登入:db.auth(‘testuser’,’testpwd’)

2、修改密碼

首先進入目標庫:

use test

db.changeUserPassword('testuser','testPWD');

3、新增角色

首先進入目標庫:

use test

db.grantRolesToUser(  "testuser",  [    { role: "read",db:"admin"}  ] )

4、回收角色許可權

首先進入目標庫:

use test

db.revokeRolesFromUser("testuser",[   { role: "read",db:"admin"}  ] )

5、刪除使用者

首先進入目標庫:

use test

db.dropUser("testuser")

6、注意

在該庫下建立的帳號,不能直接在其他庫驗證,只能在帳號建立庫下認證,再去其他庫進行操作。

命名規範

文件

       文件就是鍵值對的一個有序集。例如:{“greeting”:”hello, world! ”,“foo”:“3”},其中“greeting”和“foo”是鍵,“hello,world!”和“3”是他們對應的值。

       文件的鍵是字串。除了少數例外情況,鍵可以使用任意UTF-8字元。

       1、鍵不能含有\0(空字元)。這個字元用於表示鍵的結尾。

       2、.和$具有特殊意義,只能在特定環境下使用。通常這兩個字元是被保留的;如果使用不當的話,驅動程式會有提示。

       3、MongoDB的文件不能有重複的鍵,且區分型別和大小寫。

       4、文件中的鍵/值對是有序的:{“x”:1,“y”:2}與{“y”:2,“x”:1}是不同的。

集合

       集合就是一組文件。如果將MongoDB的一個文件比喻為關係型資料庫中的一行,那麼一個集合就相當於一張表。例如,下面兩個文件可以儲存在同一個集合裡面:

{“greeting”:“hello,world!”}

{“foo”:5 }

       集合使用名稱進行標識。集合名可以是滿足下列條件的任意UTF-8字串。

1、集合名不能是空字串(””)。

2、集合名不能包含\0字元(空字元),這個字元表示集合名的結束。

3、集合名不能以“system.”開頭,這是為系統集合保留的字首。例如,system.users這個集合儲存著資料庫的使用者資訊,而system.namespaces集合儲存著所有資料庫集合的資訊。

4、使用者建立的集合不能在集合名中包含保留字元‘$’。因為某些系統生成的集合中包含$,很多驅動程式確實支援在集合名裡包含該字元。除非你要訪問這種系統建立的集合,否則不應該在集合命中包含$。

子集

MongoDB還有一個子集合的概念,就是一個集合包含幾個集合,這樣也是便於管理,比如將people的基本資訊和國籍資訊這樣放在一個people集合中有點勉強,可以直接寫成一個文件放進去,也可以用兩個子集合,一個表示基本資訊baseinfo,一個表示國籍資訊countryinfo。

資料庫

       在MongoDB中,多個文件組成集合,而多個集合可以組成資料庫。

       資料庫通過名稱來標識,這點預計和類似。資料庫名可以是滿足以下條件的任意UTF-8字串:

       1、不能是空字串(“”)。

       2、不得含有“/”、“\”、”、*、“<”、“>”、“:”、“|”、“?”、$(一個空格)、\0(空字元)。基本上,只能使用ASCII中的字母和數字。

       3、資料庫名區分大小寫,即便是在不區分大小寫的檔案系統中也是如此。簡單起見,資料庫名迎全部小寫。

       4、資料庫名最多為64位元組。

       5、保留資料庫名有:admin、local、config。

SHELL中的基本操作

在shell中檢視或操作資料會用到4個基本操作:建立、讀取、更新和刪除(即CRUD操作)。

建立

       Insert函式可將一個文件新增到集合中。舉一個儲存部落格文章的例子。首先,建立一個名為post的區域性變數,這是一個JavaScript物件,用於表示我們的文件。它會有幾個鍵:“title”、“content”和“date”(釋出日期)。

這個物件是個有效的MongoDB文件,所以可以用insert方法將其儲存到blog集合中:

也可這樣插入:

db.blog.insert({“title”:“my blog post”,“content”:“test”,“date”:“2017-10-26”})

這篇文章已被存到資料庫中。要檢視它可用呼叫集合的find方法:

>db.blog.find()

讀取

Find和findOne方法可以用於查詢集合裡的文件。若只想檢視一個文件,可用findOne:

Find和findOne可以接受一個查詢文件作為限定條件。這樣就可以查詢符合一定條件的文件。使用find時,shell會自動顯示最多20個匹配的文件,也可獲取更多文件。後續介紹。

更新

使用update修改部落格文章。Update接受至少 兩個引數:第一個是限定條件(用於匹配待更新的文件),第二個是新的文件。假設我們要給先前寫的文章增加評論功能,就需要增加一個新的鍵,用於儲存評論陣列。

首先,修改變數post,增加“comments”鍵:

然後執行update操作,用新版本的文件替換標題為“My Blog Post”的文章:

現在,文件已經有了“comments”鍵。再用find檢視一下,可以看到新的鍵:

刪除

使用remove方法可將文件從資料庫中永久刪除。如果沒有使用任何引數,它會將集合內的所有文件全部刪除。它可以接受一個作為限定條件的文件作為引數。例如,下面的命令會刪除剛剛建立的文章:

現在,集合又是空的了。

資料型別

MongoDB有著非常豐富的資料型別,如上面的name欄位是字串,age欄位是數字,當然不止這兩種。JSON只有6中資料型別,null,布林,數字,字串,陣列和物件。MongoDB在JSON的基礎上添加了一些其他的資料型別,下面來看看MongoDB的資料型別:

null:用於表示控制或者不存在的欄位,如:{"x": null}。

     布林:只有兩個值true和false。

     32位整數:shell中這個型別不可用,javascript僅支援64位浮點數,所以32位整數會被自動轉換。

     64位整數:shell中這個型別不可用,shell會使用一個特殊的內嵌文件來顯示64位整數。

     64位浮點數:shell中的數字都是這個型別,{"x": 3.14}和{"x" : 3}都是浮點數。

     因為javascript只有一種數字型別就是64位浮點型,所以MongoDB中從shell的來的數字都被當做64位浮點型,而MongoDB中支援三種數字型別,所以用shell修改過資料庫中的資料後都會被轉換成64位浮點型。64位整數並不能精確的表示64位浮點型,如果MongoDB中存入了一個64位整數,在shell中檢視時,如果能夠表示64位浮點型那就用一個鍵的內建文件顯示而且這個值是精確的,否則,他會顯示一個多鍵內嵌文件,表示可能不精確。

     如果是64位整數3,那麼在shell中查詢顯示會是這個樣子:

db.nums.findOne() 

        "_id" : ObjectId("4c0beecfd096a2580fe6fa08"), 

        "myInteger" : { 

                "floatApprox" : 3 

    } 

}

如果是64位整數9223372036854775807,那麼在shell中查詢顯示會是這個樣子:

db.nums.findOne()

{

"_id" : ObjectId("4c0beecfd096a2580fe6fa08"),

"myInteger" : {

"floatApprox" : 9223372036854775807,

"top" : 2147483647,

"bottom" : 4294967295

}

}

topbottom分別表示高32位和低32位。

字串:UTF-8字串都可表示為字串型別的資料,如:{"name" : "Mary"}。

符號:shell不支援這種型別,shell會將資料庫中的符號型別轉換成字串。

物件id:物件id是文件的12位元組的唯一ID。

MongoDB中儲存的文件必須有一個鍵"_id",這個鍵可以是任意型別的,預設是ObjectId物件,當我們存入文件時不指定該鍵,那麼MongoDB會自動新增這樣一個鍵值對,這個值是唯一標識,ObjectId使用12位元組的儲存空間。

日期:日期型別儲存的是從標準紀元開始的毫秒數,不儲存時區,如:{"x": new Date()}。

javascript中Date物件用作MongoDB的日期型別,建立日期物件要用new Date()而不是Date(),返回的是對日期的字串表示,而不是真正的Date物件。

正則表示式:文件中可以包含正則表示式,採用javascript的正則表示式語法,如:{"x" : /foobar/i}。

程式碼:文件中還可以包含javascript程式碼,如:{"x" : function(){/*...*/}}。

二進位制資料:二進位制資料可以由任意位元組的串組成,不過shell中無法使用。

最大值:BSON包括一個特殊型別,表示可能的最大值,shell中沒有這個型別。

最小值:BSON包括一個特殊型別,表示可能的最小值,shell中沒有這個型別。

未定義:文件中也可以使用未定義型別,如:{"x" :undefined}

陣列:值的集合或者列表可以表示成陣列,陣列中的元素可以是不同型別的資料,如:{"x": ["a", "b", "c", 20]}。

內嵌文件:文件可以包含別的文件,也可以作為值嵌入到父文件中,如:{"x": {"foo" : "bar"}}。

在我目前用的情況,布林,數字,字串,日期,陣列和內嵌文件是用的最多的。

增刪改查

新增資料

insert新增時如果主鍵重複則報錯,而save新增時主鍵重複則覆蓋

db.cname.insert({name:"zhangsan", age:23})

db.cname.save({name:"zhangsan", age:23})

刪除資料

刪除資料比較簡單:

1.帶條件刪除

>db.user.remove({"name":"zhangshan"});

2.刪除所有資料

>db.user.remove({})

3.刪除集合

>db.user.drop()

4.刪除整個資料庫

>show dbs;

>db.user.getDB()

>db.dropDatabase()

刪除文件是永久性的,不能撤銷,也不能恢復的。因此,在執行remove()函式前先用find()命令來檢視下是否正確。

mongodb刪除集合後磁碟空間不釋放,用db.repairDatabase()去修復才能釋放。但是在修復的過程中如果出現了非正常的mongodb的掛掉,再次啟動時啟動不了的,需要先修復才可以,可以利用./mongod--repair --dbpath=/data/mongo/,如果你是把資料庫單獨的放在一個資料夾中指定dbpath時就指向要修復的資料庫就可以,修復可能要花費很長的時間,在使用db.repairDatabase()去修復時一定要停掉讀寫,並且mongodb要有備機才可以,不然千萬不要隨便使用db.repairDatabase()來修復資料庫,切記。

修改資料

1). update()

db.collection.update( criteria, objNew,upsert, multi )四個引數的說明如下:

criteria: update的查詢條件,類似sql update查詢內where後面的

objNew: update的物件和一些更新的操作符(如$,$inc...)等,也可以理解為sql update查詢內set後面的

upsert: 這個引數的意思是,如果不存在update的記錄,是否插入objNew,true為插入,預設是false,不插入。

multi: mongodb預設是false,只更新找到的第一條記錄,如果這個引數為true,就把按條件查出來多條記錄全部更新。

幾個查詢例子如下:

db.mytest.update({count:{$gt:1}},{$set:{name:"ok"}})              

只更新第一條記錄

db.mytest.update({count:{$gt:3}},{$set:{name:"ok"}},false,true)    

大於3的全部更新了

db.mytest.update({count:{$gt:4}},{$set:{name:"ok123"}},true,false)  

只更新了一條

db.mytest.update({count:{$gt:6}},{$set:{name:"ok123"}},true,true)  

大於6的全部更新了

2). save()

db.collection.save(x):  x是要插入的物件,效果與上面的insert命令一樣。save與insert的區別是這樣的:

在進行插入資料的操作中,當遇到_id相同的情況下,save完成儲存操作,insert則會儲存;即_id相同情況下,save相當於更新操作。 

3). $inc

用法:{$inc:{field:value}}   意思是對一個數字欄位field增加value:

[plain] 

> db.mytest.find({_id:1})       

{ "_id" : 1, "name" : "test1", "count" : 1 }  

> db.mytest.update({_id:1},{$inc:{count:1}})  

> db.mytest.find({_id:1})  

{ "_id" : 1, "name" : "test1", "count" : 2 }  //count欄位加1  

value的值也可以為負,就相當於減一個值:

[plain] 

> db.mytest.update({_id:1},{$inc:{count:-2}})  

> db.mytest.find({_id:1})  

{ "_id" : 1, "name" : "test1", "count" : 0 }  //值從2減到0  

4). $set命令

用法:{$set:{field:value}}

相當於在關係型資料庫中sql的setfield=value,全部資料型別都支援$set操作

[plain] 

> db.mytest.update({_id:1},{$set:{count:111}})  

> db.mytest.find({_id:1})  

{ "_id" : 1, "name" : "test1", "count" : 111 }   //修改數值型  

> db.mytest.update({_id:1},{$set:{name:"MongoDB"}})  

> db.mytest.find({_id:1})  

{ "_id" : 1, "count" : 111, "name" : "MongoDB" }   //修改字元型  

5). $unset

用法:{$unset:{field:1}}

> db.mytest.find({_id:1})  

{ "_id" : 1, "count" : 111, "name" : "MongoDB" }  

> db.mytest.update({_id:1},{$unset:{name:1}})  

> db.mytest.find({_id:1})  

{ "_id" : 1, "count" : 111 }  //刪除了欄位name  

 6).$push

用法:{$push:{field:value}}

把value追加到field中取,field一定是資料型別才行,如果field不存在,會新增一個數組型別加進去:

[plain] 

>db.mytest.update({_id:15},{$set:{array:["aaa","bbb"]}}) 

> db.mytest.find({_id:15})  

{ "_id" : 15,"array" : [  "aaa",  "bbb" ],"count" : 15, "name" : "ok123" }  

使用push追加資料:

[plain] 

> db.mytest.update({_id:15},{$push:{array:"ccc"}})  

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "aaa",  "bbb",  "ccc" ], "count" : 15, "name" : "ok123" }  

push一次只能追加一個值,如果需要追加多個值,則需要使用$pushAll:

[plain] 

> db.mytest.update({_id:15},{$pushAll:{array:["ddd","eee","fff"]}})  

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "aaa",  "bbb",  "ccc",  "ddd",  "eee",  "fff" ], "count" : 15, "name" : "ok123" }  

7). $addToSet

用法:{$addToSet:{field:value}}

增加一個值到陣列內,而且只有當這個值不在陣列內才增加:

[plain] 

> db.mytest.update({_id:15},{$addToSet:{array:"123"}})  

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "aaa",  "bbb",  "123" ], "array2" : [  "mmm",  "nnn"], "count" : 15, "name" : "ok123" }  

> db.mytest.update({_id:15},{$addToSet:{array:"aaa"}})  

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "aaa",  "bbb",  "123" ], "array2" : [  "mmm",  "nnn"], "count" : 15, "name" : "ok123" }  

 8). $pop

刪除陣列內的一個值,刪除最後一個值:{$pop:{field:1}} ,刪除第一個值:{$pop:{field:-1}}

[plain] 

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "aaa",  "bbb",  "123" ], "array2" : [  "mmm",  "nnn"], "count" : 15, "name" : "ok123" }  

> db.mytest.update({_id:15},{$pop:{array:1}})  

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "aaa",  "bbb" ], "array2" : [  "mmm",  "nnn" ], "count" : 15, "name" : "ok123" }  

 9).$pull

用法:$pull:{field:value}   從陣列中刪除一個等於value的值:

[plain] 

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "aaa",  "bbb" ], "array2" : [  "mmm",  "nnn" ], "coun  

t" : 15, "name" : "ok123" }  

> db.mytest.update({_id:15},{$pull:{array:"aaa"}})  

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "bbb" ], "array2" : [  "mmm",  "nnn" ], "count" : 15,  

 "name" : "ok123" }  

 10).$pullAll

用法同$pull,可以一次刪除陣列內的多個值:

[plain] 

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "bbb" ], "array2" : [  "mmm",  "nnn" ], "count" : 15,"name" : "ok123" }  

> db.mytest.update({_id:15},{$pullAll:{array2:["mmm","nnn"]}})  

> db.mytest.find({_id:15})  

{ "_id" : 15, "array" : [  "bbb" ], "array2" : [ ], "count" : 15, "name" : "ok123" }  

11). $

可以理解為陣列定位器,看一個官方文件的例子:

[plain] 

> t.find()  

{ "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] }  

> t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}})  

> t.find()  

{ "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }  

需要注意的是,$只會找到第一條陣列項,後面的就不管了:

[plain] 

> db.mytest.find({_id:16})  

{ "_id" : 16, "x" : [  1,  2,  3,  1 ] }  

> db.mytest.update({x:1},{$inc:{"x.$":1}})  

> db.mytest.find({_id:16})  

{ "_id" : 16, "x" : [  2,  2,  3,  1 ] }  

還有一點需要注意,當$配合$unset使用的時候,會留下一個null的陣列項,這個問題可以使用{$pull:{x:null}}解決:

[plain] 

> db.mytest.find({_id:16})  

{ "_id" : 16, "x" : [  2,  2,  3,  1 ] }  

> db.mytest.update({x:3},{$unset:{"x.$":1}})  

> db.mytest.find({_id:16})  

{ "_id" : 16, "x" : [  2,  2,  null,  1 ] }  

> db.mytest.update({_id:16},{$pull:{x:null}})  

> db.mytest.find({_id:16})  

{ "_id" : 16, "x" : [  2,  2,  1 ] }  

查詢資料

第一種,mongodb的資料查詢可以通過find()來查詢,有幾種常見的查詢方式:

db.user.find() 查詢出所有物件,這應該是最簡單的全部查詢的寫法

第二種,使用遊標來查詢

var cursor=db.user.find();

while(cursor.hasNext()) printjson(cursor.next());

第三種,普通查詢,遊標可以看成為陣列,可以查詢陣列上特定位置的值。

Var cursor = db.user.find();

While(cursor.hasNext())   printjson(cursor[4])

第四種,陣列:

Var arr = db.user.find().toArray();

Printjson(arr[3]);

條件資料查詢

1,條件資料查詢

就是在查詢中加入過濾條件,mongodb的精確過濾條件是制定查詢資料中json資料。 例如 db.user.find({“age”;”20”}) 相當於sql中的 select *from user where age = ‘20’

2,findOne() 

mongodb為了減少遊標的記憶體開銷提供的方法,可以加過濾條件

. db.user.findOne()

. db.user.findOne({“name”:”wpz”})

這兩種寫法都是合法的。

3,mongodb還提供limit來限制條數

. db.user.find().limit(2)

. db.user.find({“name”:”wpz”}).limit(2)

4,條件符查詢

mongodb支援< <= > >= 四種運算子查詢

db.user.find({“age”:{$gt:30}}) age大於30

db.user.find({“age”:{$lt:30}}) age小於30

db.user.find({“age”:{$gte:30}}) age大於或等於30

db.user.find({“age”:{$lte:30}}) age小於或等於30

多條件查詢

db.user.find({“age”:{,gt:10,lte:30}})

5,匹配所有

$all 這個操作符號類似於sql中的in運算子,但是不同的是in只需要滿足 一個值,但是alll需要滿足所有值。

db.user.find({“age”:{$all:[6,8]}});

6,查詢某一個欄位是否存在:$exists

db.user.find({“password”:{$exists:true}}); password存在的記錄

db.user.find({“password”:{$exists:false}}); password不存在的記錄

7,null值得處理

null處理比較奇怪,因為mongodb中的資料集合不能指定特定的格式,沒有sql中的欄位的概念,就是說,在同一個集合中有的欄位在一條資料中存在,在另一條資料中不存在,所以,要找出改欄位是不是為空,先要判斷這個欄位是不是存在才行。

db.user.find({age:{“in":[null],"exists”:true}});

8,取模運算 $mod

查詢所有age取模10之後為0 的資料,即查詢age為10的倍數的欄位:

db.user.find({age:{$mod:[10,0]}});

10,不等於 $ne –> (not equals)

查詢所有age不等於10 的資料

db.user.find({age:{$ne:10}});

11,包含 $in

查詢所有age等於10 或者20 的資料

db.user.find({age:{$in:[10,20]}});

12,不包含 $nin

查詢所有age不等於10 或者20 的資料

db.user.find({age:{$nin:[10,20]}});

13,陣列元素的個數 $size

查詢age資料元素個數為3的資料

db.user.find({age:{$size:3}});

14,正則表示式匹配查詢

name不以wpz開頭的資料

db.user.find({“name”:{$not:/^wpz.*/}});

15,count查詢條數

- db.user.find().count();

16,skip 設定查詢資料的起點

查詢從第三條資料之後的五條資料

- db.user.find().skip(3).limit(5);

17,排序 sort

- db.user.find().sort({age:1}); 按照age升序

- db.user.find().sort({age:-1}); 按照age降序

18,極值操作符

下面的四個操作符可用於得到資料集合中的“邊緣”值。

(1)“$max”:expr

返回組內的最大值

(2)“$min”:expr

返回組內的最小值

(1)“$first”:expr

返回分組的第一個值,忽略後面所有的值。只有排序之後,明確知道資料順序時這個操作才有意義。

(1)“$last”:expr

與first相反,返回分組的最後一個值。

“$max”和“$min”會檢視每一個文件,以便得到極值。因此,若資料是無序的,這兩個操作符也可以有效工作;如果資料是有序的,這兩個操作符就會有些浪費。假設有一個存有學生考試成績的資料集,需要找到其中的最高分與最低分:

 另一方面,如果資料集是按照希望的欄位排序過,那麼first和last更高效,且結果相同。

索引

索引的種類

1:_id索引:是絕大多數集合預設建立的索引,對於每個插入的資料,MongoDB都會自動生成一條唯一的_id欄位 
2:單鍵索引:是最普通的索引

與_id索引不同,單鍵索引不會自動建立 如:一條記錄,形式為:{x:1,y:2,z:3}

db.imooc_2.getIndexes()//檢視索引

db.imooc_2.ensureIndex({x:1})//建立索引,索引可以重複建立,若建立已經存在的索引,則會直接返回成功。

db.imooc_2.find()//檢視資料

3:多鍵索引 
多鍵索引與單鍵索引建立形式相同,區別在於欄位的值。 
1)單鍵索引:值為一個單一的值,如字串,數字或日期。 
2)多鍵索引:值具有多個記錄,如陣列。

db.imooc_2.insert({x:[1,2,3,4,5]})//插入一條陣列資料

4:複合索引:查詢多個條件時,建立複合索引 
例如{x:1,y:2,z:3}這樣一條資料,要按照x與y的值進行查詢,就需要建立複合索引。

db.imooc_2.ensureIndex({x:1,y:1}) #1升序,-1降序

db.imooc_2.find({x:1,y:2}) #使用複合索引查詢

5:過期索引 
在一段時間後會過期的索引 
在索引過期後,相應的資料會被刪除 
適合儲存在一段時間之後會失效的資料,比如使用者的登入資訊、儲存的日誌等。 

db.imooc_2.ensureIndex({time:1},{expireAfterSeconds:10}) #建立過期索引,time-欄位,expireAfterSeconds在多少秒後過期,單位:秒

db.imooc_2.ensureIndex({time:1},{expireAfterSeconds:30}) #time索引30秒後失效

db.imooc_2.insert({time:new Date()}) #new Date()自動獲取當前時間,ISODate

db.imooc_2.find() #可看到剛才insert的值

過30秒後再find,剛才的資料就已經不存在了。

過期索引的限制: 
(1)儲存在過期索引欄位的值必須是指定的時間型別,必須是ISODate或者ISODate陣列,不能使用時間戳,否則不能自動刪除。 
例如 >db.imooc_2.insert({time:1}),這種是不能被自動刪除的 
(2)如果指定了ISODate陣列,則按照最小的時間進行刪除。 
(3)過期索引不能是複合索引。因為不能指定兩個過期時間。 
(4)刪除時間是不精確的。刪除過程是由MongoDB的後臺程序每60s跑一次的,而且刪除也需要一定時間,所以存在誤差。

6:全文索引:對字串與字串陣列建立全文課搜尋的索引 。
不適用全文索引:查詢困難,效率低下,需要正則匹配,逐條掃描。 
使用全文索引:簡單查詢即可查詢需要的結果。

建立方式:

db.articles.ensureIndex({key:"text"}) #key-欄位名,value-固定字串text

上述指令表示,在articles這個集合的key欄位上建立了一個全文索引

db.articles.ensureIndex({key1:"text",key2:"text"}) #在多個欄位上建立全文索引

對於nosql資料庫,每個記錄儲存的key可能都是不同的,如果要在所有的key上建立全文索引,一個一個寫很麻煩,mongodb可以通過下面指令完成:

db.articles.ensureIndex({"$**":"text"}) #給所有欄位建立全文索引

全文索引的建立: 
1:可以為一個欄位建立全文索引 
2:可以為多個欄位建立全文索引 
3:可以為集合中所有的欄位建立全文索引 
注意:上面三種建立全文索引的方式,前兩個方式類似,第三個需要一個特殊的字串來表示——”$**”,我想如果集合中就兩三個欄位,也可以使用2來建立這樣的全文索引,如果這個集合總就一個欄位使用1也是可以的,3僅僅是為了統一化而已。

全文索引的查詢: 
1:使用全文索引查詢不需要指定全文索引的欄位名字——直接使用$text,$search即可 
2:在MongoDB中每個資料集合只允許建立一個全文索引,不過這個全文索引可以針對一個、多個、全部的資料集合的欄位來建立。 
3:查詢多個關鍵詞,可以使用空格將多個關鍵詞分開——空格——或的關係 
4:指定不包含的欄位使用-來表示—— -:非的關係 
5:引號包括起來代表與的關係—— \”\”:與的關係

db.articles.find({$text:{$search:"coffee"}})

db.articles.find({$text:{$search:"aa bb cc"}}) #空格代表或操作,aa或bb或cc

db.articles.find({$text:{$search:"aa bb -cc"}}) #-號為非操作,即不包含cc的

db.articles.find({$text:{$search: "\"aa\" \"bb\" \"cc\""}}) #加雙引號可以提供與關係操作

相似度查詢:

搜尋排序,查詢結果與你查詢條件越相關的越排在前面。 
MongoDB中可以使用$meta操作符完成,格式:

{score:{$meta: "textScore"}}

在全文搜尋的格式中加入這樣一個條件,如下:

db.imooc_2.find({$text:{$search:"aa bb"}},{score:{$meta:"textScore"}})

搜尋出的結果會多出一個score欄位,這個得分越高,相關度越高。 
還可以對查詢出的結果根據得分進行排序:

db.imooc_2.find({$text:{$search:"aabb"}},{score:{$meta:"textScore"}}).sort({score:{$meta:"textScore"}})

加上.sort方法即可。

全域性索引的限制: 
1.每次查詢,只能指定一個$text查詢 
2.$text查詢不能出現在$nor查詢中 
3. 查詢中如果包含了$text, hint不再起作用(強制指定索引hint) 
4. MongoDB全文索引還不支援中文

7:地理位置索引 
將一些點的位置儲存在MongoDB中,建立索引後,可以按照位置來查詢其他點。

地理位置索引分為兩類: 
1.2D索引,用於儲存和查詢平面上的點。 
2.2Dsphere索引,用於儲存和查詢球面上的點。 
例如: 
查詢距離某個點一定距離內的點。 
查詢包含在某區域內的點。

分為2種:2D平面地理位置索引和 2D sphere 2D球面地裡位置索引 2者的區別在於計算距離時使用的計算方式不同(平面距離還是球面距離)

2D地理位置索引建立方式

db.collection.ensureIndex({w:”2d”})

2D地理位置索引的取值範圍以及表示方法經緯度[經度,緯度] 
經緯度取值範圍 經度[-180,180] 緯度[-90,90]

db.collection.insert({w:[180,90]})

2D地理位置查詢有2種 
1.使用$near 查詢距離某個點最近的點 ,預設返回最近的100個點

db.collection.find({w:{$near:[x,y]}})

可以使用$maxDistance:x 限制返回的最遠距離

db.collection.find({w:{$near:[x,y],$maxDistance:z}})

2.使用$geoWithin 查詢某個形狀內的點 
形狀的表示方式:

1. $box 矩形,使用{$box:[[x1,y1],[x2,y2]]}

2. $center 圓形,使用 {$center:[[x,y],r]}

3. $polygon 多邊形,使用 {$polygon:[[x1,y1],[x2,y2],[x3,y3]]}

mongodb geoWithin 查詢

查詢矩形中的點

db.collection.find({w:{$geoWithin:{$box:[[0,0],[3,3]]}}})

查詢圓中的點

db.collection.find({w:{$geoWithin:{$center:[[0,0],5]}}})

查詢多邊形中的點

db.collection.find({w:{$geoWithin:{$polygon:[[0,0],[0,1],[2,5],[6,1]]}}})

mongodb geoNear 查詢

geoNear 使用 runCommand命令操作

db.runCommand({

geoNear:"collection名稱",

near:[x, y],

minDistance:10(對2d索引無效,對2Dsphere有效')

maxDistance:10

num:1 返回數量

})

可返回最大距離和平均距離等資料.

返回的資料: 
results:查詢到的資料;dis:距離,obj:資料記錄 
stats:查詢引數,maxDistance最大距離和avgDistance平均距離 
ok:1,查詢成功

mongodb 2Dsphere索引詳解

2Dsphere index create method 
use command:

db.collection.ensureindex({key: '2dsphere'})

2Dsphere位置表示方式: 
GeoJSON:描述一個點,一條直線,多邊形等形狀。 
格式:

{type:'', coordinates:[list]}

GeoJSON查詢可支援多邊形交叉點等,支援MaxDistance 和 MinDistance

索引的屬性

建立索引的格式:

db.collection.ensureIndex({indexValue},{indexProperty})

其中:indexProperty比較重要的有 
1:名字

db.collection.ensureIndex({indexValue},{name:})

MongoDB會自動的建立,規則是key_1 或者 key_-1 1或者-1代表排序方向,一般影響不大,長度一般有限制125位元組 
為了見名知意我們可以自己來命名

自定義索引名稱方式:

db.imooc_2.ensureIndex({x:1,y:1,z:1,m:1},{name:"normal_index"})

刪除索引

db.imooc_dropIndex(indexName)

刪除索引時,可以通過我們定義的名字來刪除索引

db.imooc_2.dropIndex("normal_index")

2:唯一性:不允許在同一個集合上插入具有同一唯一性的資料。

db.imooc_2.ensureIndex({x:1,y:1,z:1,m:1},{unigue:true)

3:稀疏性

db.collection.ensureIndex({},{sparse:true/false}) #指定索引是否稀疏

MongoDB索引預設是不稀疏的。 
稀疏性的不同代表了MongoDB在處理索引中存在但是文件中不存在的欄位的兩種不同的方法。 
例如,我們為一個collection的x欄位指定了索引,但這個collection中可以插入如{y:1,z:1}這種不存在x欄位的資料, 
如果索引為不稀疏的,mongodb依然會為這個資料建立索引,如果在建立索引時指定為稀疏索引,那麼就可以避免這件事情發生了。

db.imooc_2.insert({"m":1})

db.imooc_2.insert({"n":1})

通過$exists可以判斷欄位是否存在,如

db.imooc_2.find({m:{$exists:true}}) #篩選出有m欄位的文件

給這個文件的m欄位建立一個稀疏索引:

db.imooc_2.ensureIndex({m:1},{sparse:true})

第二條文件不存在m欄位,所以不會建立這個索引 
如果使用稀疏索引查詢不存在稀疏索引欄位的文件,mongodb則不會使用這個索引查詢 
例如:

db.imooc_2.find({m:{$exists:false}}) #可以查到資料

但如果我們通過hint強制使用索引,就不會查到資料了

db.imooc_2.find({m:{$exists:false}}).hint("m_1") #查不出資料,因為n上並沒有m欄位的索引

聚合

       MongoDB中的聚合aggregate主要用於處理資料計算。

聚合框架

使用聚合框架可以對集合中的文件進行變換和組合。基本上,可以用多個構件建立一個管道(pipeline),用於對一連串的文件進行處理。這些構架包括篩選(filtering)、投射(projecting)、分組(grouping)、限制(limiting)和跳過(skipping)。

例如一個儲存著動物型別的集合,希望找出最多的那種動物,假設每種動物被儲存為一個mongodb文件,可以按照以下步驟建立管道。

1)將每個文件的動物名稱映射出來。

2)安裝名稱排序,統計每個名稱出現的次數。

3)將文件按照名稱出現的次數降序排列。

4)將返回結果限制為前五個。

具體操作符:

1){"$porject",{"name" : 1}}

類似於查詢階段的欄位選擇器,指定"fieldname": 1選定需要的欄位,"fieldname" : 0排除不需要的欄位,"_id"欄位自動顯示。結果儲存在記憶體中,不會寫入磁碟。

db.test_collection.aggregate({"$project" : {"name" : 1}});    =>

{ "_id" : ObjectId("535a2d3c169097010b92fdf6"), "name" : "snake" }

2){"$group", {"_id" : "$name","count" : {"$sum" : 1}}}

首先指定了分組的欄位"name",該操作執行完後,每個name只對應一個結果,所有可以將name指定為唯一識別符號"_id"。第二個欄位表明分組內的每個文件"count"欄位加1。新加入的文件中不會有count欄位。

db.test_collection.aggregate({"$project" : {"name" : 1}}, {"$group" : {"_id" : "$name", "count" : {"$sum" : 1}}});

=>

{ "_id" : "bird", "count" : 8344 }

{ "_id" : "snake", "count" : 8443 }

{ "_id" : "cat", "count" : 8183 }

{ "_id" : "rabbit", "count" : 8206 }

{ "_id" : "tiger", "count" : 8329 }

{ "_id" : "cow", "count" : 8309 }

{ "_id" : "horse", "count" : 8379 }

{ "_id" : "dog", "count" : 8406 }

{ "_id" : "dragon", "count" : 8372 }

{ "_id" : "elephant", "count" : 8264 }

{ "_id" : "pig", "count" : 8403 }

{ "_id" : "lion", "count" : 8362 }

3){"$sort" :{"count" : -1}}

對結果集中的文件根據count欄位做降序排列。

4){"$limit" : 5}

將返回結果限制為5個文件。

將上述結果綜合起來:

db.test_collection.aggregate(

{

"$project" : {"name" : 1}},

{"$group" : {"_id" : "$name", "count" : {"$sum" : 1}}},

{"$sort" : {"count" : -1}},

{"$limit" : 5}

);

aggregate會返回一個文件陣列,內容為出現次數最多的5個動物:

{ "_id" : "snake", "count" : 8443 }

{ "_id" : "dog", "count" : 8406 }

{ "_id" : "pig", "count" : 8403 }

{ "_id" : "horse", "count" : 8379 }

{ "_id" : "dragon", "count" : 8372 }

除錯過程中。可以逐一對管道符進行排查。
聚合框架不能對集合進行寫入操作,所有結果返回給客戶端,聚合結果必須限制在16M以內。

管道操作符

每個操作符都會接受一連串的文件,對這些文件進行型別轉換,最後得到的文件作為結果傳遞給下一操作符。

不同的管道操作符可以將任意順序組合在一起使用,而且可以被重複任意多次。

1、 $match

$match用於對文件集合進行篩選,之後得到的文件子集做聚合。

"$match"支援所有的常規查詢操作符("$gt","$lt","$ne")等,不能使用地理空間操作符。

實際操作中儘量將"$match"放在管道的前面部分,一方面可以提快速將不需要的文件過濾掉,另外在對映和分組前篩選,查詢可以使用索引。

2、 $project

使用"$project"可以提取欄位,可以重新命名欄位,

db.foo.aggregate({"$project" : {"city" : 1, "_id" : 0}})    =>

{ "city" : "NEW WORK" }

可以將投射過的欄位重新命名:

db.foo.aggregate({"$project" : {"newcity" : "$city", "_id" : 0}})    =>

{ "newcity" : "NEW WORK" }

使用"$fieldname"語法為了在聚合框架中引用fieldname欄位,例如上面"$city"會被替換為"NEW WORK"。

對欄位重新命名後,Mongdb不會記錄其記錄欄位的歷史名稱,所以應該在修改欄位名稱前使用索引。

數學表示式

數學表示式用來操作資料運算。

db.foo.aggregate(

  {"$project" :

    {"total" :

      {"$add" : ["$age", "$year"]},

      "_id" : 0

    }

  }

)

{"total" : 15}

可以將多個表示式組合為更為複雜的表示式:

db.foo.aggregate(

  {"$project" :

    {"sub" :

      {"$subtract" : [{"$add" : ["$age", "$year"]}, 7]},

      "_id" : 0

    }

  }

)

{ "sub" : 8 }

操作符語法:

1)將表示式相加:"$add" : [expr1,[, expr2, ..., exprN]]

2)達式1減去表示式2:"$subtract": [expr1, expr2]

3)將表示式相乘:"$multiply" :[expr1, [, expr2, ..., exprN]]

4)表示式1除以表示式2得到商:"$divide": [expr1, expr2]

5)表示式1除以表示式2得到餘數:"$mod": [expr1, expr2]

日期表示式

用於提取日期資訊的表示式:"$year","$month","$week","$dayOfMonth","$dayOfweek","$hour","$minute","$second"。只能對日期型別的欄位進行日期操作,不能對數值型別進行日期操作。

db.bar.insert({"name" : "pipi", "date" : new Date()})

db.bar.aggregate(

  {"$project" :

    {"birth-month" :

      {"$month" : "$date"},

      "_id" : 0

    }

  }

)

{ "birth-month" : 4 }

也可以使用字面量日期。

db.bar.aggregate(

  {"$project" :

    {"up-to-now" :

      {"$subtract" : [{"$minute" : new Date()}, {"$minute" : "$date"}]},

      "_id" : 0

    }

  }

)

{ "up-to-now" : 18 }

操作符語法:

1)"$substr": [expr,startOffset, numoReturn]

接受字串,起始位置以後偏移N個位元組,擷取字串。

2)"$concat": [expr1[,expr2, ..., exprN]]

將給定的表示式連線在一起作為返回結果。

3)"$toLower": expr

返回引數的小寫形式

4)"$toUpper": expr

返回引數的大寫形式

例如:

db.foo.insert({"firstname" : "caoqing", "lastname" : "lucifer"})

db.foo.aggregate(

{

  "$project" : {

    "email" :