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 } } |
top和bottom分別表示高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" : |