概要
下面開始學習MongoDB最重要也是最基礎(chǔ)的部分:C(創(chuàng)建)R(查詢)U(更新)D(刪除);由于R(查詢)操作相對來說內(nèi)容比較多,也比較繁瑣,
同時使用頻率也比較高,所以下一篇會拿出來單獨介紹。廢話不多說,連上服務(wù)器,我們直接進入正題!
一、創(chuàng)建
按照我們關(guān)系型數(shù)據(jù)庫的思想,一個服務(wù)器要想存放數(shù)據(jù),首先要有數(shù)據(jù)庫,表,字段,約束,當然了也少不了主鍵,外鍵,索引,關(guān)系等;
但是在MongoDB的世界里邊,我們不用預(yù)先的去創(chuàng)建這些信息從而直接來使用各個屬性。
1、數(shù)據(jù)庫(database)
a)、創(chuàng)建
use mydb(創(chuàng)建并切換到名稱為mydb的數(shù)據(jù)庫實例下。注:如果你對其不進行任何操作,該數(shù)據(jù)庫是沒有任何實際意義的)
2、集合(collection)
a)、創(chuàng)建
我們直接指定,不做任何預(yù)處理,指定一個名稱為users的數(shù)據(jù)集(相當于表),并向其中插入一條用戶數(shù)據(jù)。
db.users.insert({ "name" : "wjg" , "age" : 24 })
返回結(jié)果如下,表示你已經(jīng)成功插入了一條數(shù)據(jù):
WriteResult({ "nInserted" : 1 })
b)、顯式創(chuàng)建
僅創(chuàng)建一個名稱為collectionName的,沒有任何大小和數(shù)量限制的數(shù)據(jù)集
db.createCollection("collectionName")
如果該數(shù)據(jù)集有重名,會給出已經(jīng)存在的提示:
{ "ok" : 0, "errmsg" : "collection already exists", "code" : 48 }
成功之后會給出ok的提示:
{ "ok" : 1 }
3、文檔(document)
a)、單一插入
注:如果沒有主鍵“_id”,插入文檔的時候MongoDB會為我們自動保存一個進去。
這里我們指定一個“_id”,當然了,“_id”肯定是不能重復(fù)的,否則無法插入成功。
db.users.insert({"_id":0,"name":"jack","age":20})
成功插入數(shù)據(jù)之后:
WriteResult({ "nInserted" : 1 })
b)、批量插入
注:一次性插入多個文檔會明顯提高插入速度;
插入文檔的大小限制為48MB;
如果其中有一個文檔插入失敗了,這個文檔之前的都可以插入成功,但是在它之后都會失??;(不同的驅(qū)動可能會有不同的處理方式)
db.users.insert([{"_id":1,"name":"tom","age":21},{"_id":2,"name":"joe","age":22},{"_id":3,"name":"bob","age":22}])
批量插入成功之后會返回如下信息:
BulkWriteResult({
"writeErrors":[],
"writeConcernErrors":[],
"nInserted":3,
"nUpserted":0,
"nMatched":0,
"nModified":0,
"nRemoved":0,
"upserted":[]})
分別表示的大致意思為:
插入的錯誤信息,其他的插入錯誤信息,插入的文檔數(shù)量,特殊更新的文檔數(shù)量,匹配到的文檔數(shù)量,
更新的文檔數(shù)量,移出的文檔數(shù)量和特殊文檔更新信息
特殊的文檔更新(upsert),其定義如下:
如果沒有找到符合更新條件的文檔,就會以這個條件和更新文檔為基礎(chǔ)創(chuàng)建一個新的文檔;如果找到了匹配的文檔,那么就正常更新
二、更新
想要更新文檔,必須要有兩個參數(shù):
一個是查詢條件,用于定位到需要更新的目標文檔;另一個是修改器,用于說明要對找到的文檔進行哪些修改
截至此刻為止,我們已經(jīng)向mydb數(shù)據(jù)庫中名稱為users的數(shù)據(jù)集中添加了如下幾個文檔:
a)、單一更新
讓我們來為名字為bob的年齡增加一歲,直接將年齡更新為23歲
db.users.update({"name":"bob"},{$set:{"age":23}}) //使用了$set修改器之后,只會更新age自段的值為23
或者
db.users.update({"name":"bob"},{"age":23}) //同樣會將age自段的值更新為23,但是會移出除了“_id”和本身之外的所有字段值
具體詳情如下圖:
注:如果需要更新的字段不存在,那么MongoDB會按字段順序進行插入,類似于上邊提到的特殊更新。
其實細心的童鞋會發(fā)現(xiàn),我們都是以name作為條件進行更新,所以并不能保證其唯一性,那么MongoDB只會更新匹配到的第一個文檔。
這里還是建議大家指定一個唯一的文檔進行更新,"_id"可以幫你保證!
b)、使用選擇器更新(重點)
1、$set修改器
執(zhí)行特殊更新操作;可以修改內(nèi)嵌文檔;甚至可以更改鍵的類型;
Ⅰ、假設(shè)需求改了,我們需要為為所有用戶添加一個”hobby“的屬性用于存放用戶的喜好,那么我們可以這樣做:
db.users.update({},{$set:{"hobby":"read"}}) //這樣做是錯的,哈哈。。
更新后的文檔如下:
切記:update方法只會更新它匹配到的第一個文檔對象,所以這個操作只會將名字為”wjg“的用戶添加一個”hobby“屬性,其它對象不會添加
正確方式如下:
db.users.update({},{$set:{"hobby":"write"}},false,true) //第三個參數(shù)為是否啟用特殊更新,第四個為是否更新所有匹配的文檔;
這倆參數(shù)默認都為false
更新后的文檔如下:
可以看到我們成功更新了五個文檔對象
Ⅱ、假設(shè)我們需求又變了,老板說了,每個用戶的愛好會有多個。那么簡單,因為我們可以直接將string類型的hobby屬性改成string數(shù)組類型的
db.users.update({"_id":0},{"$set":{"hobby":["write","read","paly ping-pong"]}}) //將_id為0的hobby屬性更新為數(shù)組類型的
Ⅲ、然后我們發(fā)現(xiàn)tom壓根就沒有愛好,那么我們可以使用$unset修改器將其刪除
db.users.update({"_id":1},{"$unset":{"hobby":1}}) //1表示徹底刪除這個鍵值對
Ⅳ、現(xiàn)在已經(jīng)過去一年了,我們是時候把所有用戶的年齡加一歲了。這時$inc上場
db.users.update({},{"$inc":{"age":1}},false,true) //別忘了將第四個參數(shù)置為true
注:$inc修改器只針對數(shù)字類型,如果是string或者其他類型的會提示報錯:
提示無法將$inc應(yīng)用到非數(shù)字類型上,并且給出錯誤位置:”_id“為2的文檔;
我們將joe的age改為數(shù)字類型的重新執(zhí)行一次,就可以成功啦!
Ⅴ、過了一段時間,jack又喜歡上了游泳,那么我們可以用$push這樣搞:
db.users.update({"_id":0},{"$push":{"hobby":"swim"}}) //hobby必須是一個數(shù)組,所以你在其他文檔上使用是不會成功的
Ⅵ、然而jack不喜歡讀書了,我們就用$pull來移除“read”元素
db.users.update({"_id":0},{"$pull":{"hobby":"read"}}) //它會移除數(shù)組中所有匹配到的“read”元素
另外:db.users.update({"_id":0},{"$pop":{"hobby":1}}) //表示移除hobby中的最后一個元素,為-1表示移除第一個元素
不知道大家有沒有發(fā)現(xiàn),“_id”為0的文檔從第二的位置被移動到了數(shù)據(jù)集的末尾,這是因為該文檔尺寸變大的原因?qū)е碌模?/p>
原先的位置已經(jīng)容不下它了!
那么這就引出了另外一個概念:填充因子,它是MongoDB為每個新文檔預(yù)留的增長空間。上邊的這種情況就會使填充因子增加。
移動文檔是一個非常緩慢的操作,盡量讓填充因子的值接近1;
通過db.users.stats()查看該數(shù)據(jù)集信息,“paddingFactor”即為填充因子的大??;
三、刪除
刪除文檔相對來說就簡單了許多
1、單一刪除
給定一個查詢參數(shù),只要符合條件的,都會被刪除
db.users.remove({"_id":{"$lte":1}}) //刪除“_id”的值小于等于1的所有文檔
返回結(jié)果如下:
WriteResult({"nRemoved":2}) //成功刪除了兩個文檔
2、清空整個數(shù)據(jù)集
db.users.remove()
如果數(shù)據(jù)較多的話,用db.users.drop()會明顯提升刪除速度
注:刪除都是不可逆的,不能撤銷,也不能恢復(fù),所以要謹慎使用;
清空數(shù)據(jù)集的時候集合本身并不會被刪除,也不會刪除集合的元信息;
四、未解決問題
1、先取出來再更新,使用查詢條件取出來的數(shù)據(jù)都無法用游標去獲取值,但是用findOne獲取的一個文檔對象就可以。。。
如果哪位大神知道的話麻煩告訴小弟一下,多謝、、、哈哈。。
最后一個問題已經(jīng)找到,原因如下:
第一個find操作雖然獲取的只是一個文檔對象,看似和下邊用findOne是一樣的效果,但是在MongoDB的shell中第一個的結(jié)果集是被默認為多個文檔集合,所以它無法判斷你想獲取的是哪個文檔的age。
您可能感興趣的文章:- MongoDB數(shù)據(jù)庫插入、更新和刪除操作詳解
- MongoDB插入、更新、刪除文檔實現(xiàn)代碼
- MongoDB數(shù)據(jù)更新方法干貨篇