新聞中心
MongoDB是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù)。由C++語(yǔ)言編寫(xiě)。旨在為WEB應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案。

MongoDB是一個(gè)介于關(guān)系數(shù)據(jù)庫(kù)和非關(guān)系數(shù)據(jù)庫(kù)之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫(kù)當(dāng)中功能最豐富,最像關(guān)系數(shù)據(jù)庫(kù)的。它支持的數(shù)據(jù)結(jié)構(gòu)非常松散,是類(lèi)似json的bson格式,因此可以存儲(chǔ)比較復(fù)雜的數(shù)據(jù)類(lèi)型,本篇文章重點(diǎn)為大家講解一下MongoDB的CRUD操作。
INSERT操作
MongoDB中的新增操作,把一個(gè)新的Document插入到一個(gè)Collection中。
如果該Collection不存在,則新增一個(gè)新的Collection。這個(gè)和關(guān)系數(shù)據(jù)庫(kù)有很大的區(qū)別,在關(guān)系數(shù)據(jù)庫(kù)中,我們需要定義數(shù)據(jù)庫(kù)的schema和表結(jié)構(gòu),這是NoSQL(MongoDB是NoSQL的一種)數(shù)據(jù)庫(kù)和關(guān)系數(shù)據(jù)庫(kù)很大的區(qū)別。在MongoDB中,我們可以在一個(gè)Collection中包含多個(gè)不同結(jié)構(gòu)的Document(不推薦這樣做,一個(gè)Collection最好具有相同格式的Document,便于維護(hù)和使用)。
關(guān)于”*id”字段,當(dāng)我們新增一個(gè)Document到Collection中的時(shí)候,MongoDB需要每一個(gè)新增的Document中有一個(gè)”*id”字段,MongoDB把這個(gè)字段作為主鍵,所以要求這個(gè)字段在Collection中是唯一的。如果新增的Document中沒(méi)有包含”*id”字段,那么MongoDB的客戶(hù)端會(huì)在該Document中新增一個(gè)值為ObjectId類(lèi)型的”*id” 字段;如果MongoDB服務(wù)在新增Document的時(shí)候發(fā)現(xiàn)Document中沒(méi)有”*id”字段,那么mongod會(huì)新增一個(gè)值為ObjectId類(lèi)型的”*id”字段到該Document中。
MongoDB對(duì)單個(gè)Document的寫(xiě)操作是原子的。
MongoDB提供了如下的方式來(lái)進(jìn)行新增操作:
-
db.collection.insert()
-
db.collection.insertOne()
3.2版本新增
-
db.collection.insertMany()
3.2版本新增
db.collection.insert()
insert操作可以新增單個(gè)Document,也可以新增多個(gè)Document。如果新增單個(gè)Document,則把需要新增的Document作為參數(shù)傳遞給insert(),如果新增多個(gè)Document,則將多個(gè)Document的數(shù)組作為參數(shù)傳遞個(gè)insert()函數(shù)。
比如我們需要在”post”這個(gè)collection上新增一個(gè)Document來(lái)表示我們的博客中新增了一篇文章,我們可以這么做:
現(xiàn)在,我們給post這個(gè)Collection新增了一個(gè)Document,表示在Blog中新增了一篇文章。我們可以看下現(xiàn)在post這個(gè)Collection中是不是有我們新增的Document。
這里我們使用findOne()來(lái)查詢(xún),我們可以看到,我們由于沒(méi)有在Document中包含”*id”字段,所以MongoDB自動(dòng)為我們新增了一個(gè)”*id”字段。
insert()函數(shù)可以一次新增多個(gè)Document,只要將一個(gè)Document的數(shù)組傳遞給insert()就可以了,如:
db.collection.insertOne()
insertOne()函數(shù)是在3.2版本中新增的,它用來(lái)添加單個(gè)Document。例子如下:
db.collection.insertMany()
insertMany()函數(shù)是insert的批量增加的版本,支持一次新增多個(gè)Document,它也是3.2版本中新增的函數(shù):
好了,我們簡(jiǎn)單介紹了下insert操作的三個(gè)函數(shù),下面,我們已經(jīng)在MongoDB的數(shù)據(jù)庫(kù)里新增了幾個(gè)Document了。接下來(lái),是時(shí)候開(kāi)始學(xué)習(xí)查找操作來(lái)查看這些已經(jīng)存儲(chǔ)在MongoDB的記錄了。
QUERY操作
MongoDB提供了db.collection.find()函數(shù)來(lái)執(zhí)行查詢(xún)操作,函數(shù)將返回一個(gè)游標(biāo)(cursor),用于遍歷查詢(xún)到的Documents。find()函數(shù)接受兩個(gè)參數(shù),一個(gè)是過(guò)濾條件,還有一個(gè)是投影。
db.collection.find(
,
)
-
用于查找滿(mǎn)足過(guò)濾條件的Document
-
(投影)用于指定被找到的Document中需要返回哪些字段,用于限制網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)的大小。投影的概念和關(guān)系數(shù)據(jù)庫(kù)中的投影的概念基本是一致的。
現(xiàn)在,我們可以查詢(xún)下剛才我們新增的所有的Documents,通過(guò)find(),我們來(lái)看下如何查詢(xún):
如果我們沒(méi)有傳遞任何參數(shù),或者傳遞一個(gè)”{}”給find()函數(shù),那會(huì)find()返回Collection中所有的Document。現(xiàn)在,可以看到我們剛才新增的所有的Documents。
接下來(lái),我們通過(guò)指定條件,查詢(xún)標(biāo)題為”Third Post”的Document,我們可以這樣做:
發(fā)現(xiàn)了么,我們的查詢(xún)條件其實(shí)就是以Document方式構(gòu)造的。在MongoDB中,我們可以通過(guò)構(gòu)造不同的Document來(lái)定義不同的查詢(xún)條件。
除了使用具體的字段來(lái)過(guò)濾,我們還可以使用查詢(xún)操作符來(lái)做更加靈活的操作。我們現(xiàn)在需要查找出標(biāo)題是”Third Post”或”Fifth Post”這兩篇Post中的任何一篇,我們可以使用**$in**操作符來(lái)查詢(xún):
除了使用**,還提供了很多有用的操作符來(lái)幫助構(gòu)造過(guò)濾條件,如lt**, and, $or等。
使用子Document中值作為過(guò)濾條件
現(xiàn)在,我們假設(shè)有一篇文章,在Document中的存儲(chǔ)如下:
現(xiàn)在,我們需要匹配內(nèi)部Document中的條件,比如我們需要查找author中name是Duke的記錄,我們可以這樣構(gòu)造我們的篩選條件:
db.post.findOne(
{
"author":
{
"name": "Duke",
"email": "740313507@qq.com"
}
})
查詢(xún)結(jié)果就是這樣的
我們觀(guān)察這個(gè)過(guò)濾條件,發(fā)現(xiàn)和上面的過(guò)濾條件的結(jié)構(gòu)一樣,就是{“field”:”value”}的格式,只是不同的是,這次的”value”不再是一個(gè)普通的值了,而是一個(gè)Document。通過(guò)這種方式來(lái)過(guò)濾,具有一些局限性,我們?nèi)绻檎襛uthor中name是Duke的記錄,我們必須完整指定author的值,也就是需要完整的Document。如果需要只過(guò)濾name,而不關(guān)系email的值,我們可以這樣構(gòu)造過(guò)濾條件:
db.post.findOne({"author.name": "Duke"})
查詢(xún)到和上面一樣的結(jié)果
但是,這次我們使用了”author.name”的方式來(lái)指定field。這種類(lèi)似于成員引用的”點(diǎn)符號(hào)”結(jié)構(gòu)的查詢(xún),可以用來(lái)對(duì)內(nèi)嵌的Document中的指定的field進(jìn)行過(guò)濾。后面你將會(huì)看到,對(duì)于數(shù)組類(lèi)型的值,也可以通過(guò)類(lèi)似的方式來(lái)構(gòu)造過(guò)濾條件。
使用數(shù)組中的元素作為過(guò)濾條件
接下來(lái)我們看下如何使用數(shù)組中的值來(lái)構(gòu)造過(guò)濾條件。最簡(jiǎn)單的,也是最容易想到的,就是把整個(gè)數(shù)組作為過(guò)濾條件,類(lèi)似于上面的把整個(gè)子Document作為過(guò)濾條件一樣,我們可以這樣構(gòu)造
db.post.findOne({"comments": ["comment one", "comment two"]})
查詢(xún)的結(jié)果如下:
但是,這種方式?jīng)]法指定數(shù)組中的某個(gè)值作為過(guò)濾件。如果要使用數(shù)組中的某個(gè)值作為過(guò)濾條件,我們可以這么構(gòu)造過(guò)濾條件:
db.post.find({"comments": "comment two"})
查詢(xún)到的結(jié)果如下:
這里最后使用了”pretty()”方法來(lái)格式化輸出,輸出格式化的數(shù)據(jù),便于觀(guān)察,僅此而已,沒(méi)有別的用途。我們可以看到,這種方式構(gòu)造的過(guò)濾條件,使用了數(shù)組中的一個(gè)元素來(lái)篩選記錄,只要數(shù)組中包含了這個(gè)元素(不管這個(gè)元素的下標(biāo)),那么就會(huì)過(guò)濾出這條記錄,有點(diǎn)像集合中的in操作。這種方式可以匹配數(shù)組中的一個(gè)元素。
接下來(lái),我們更近一步,我們需要匹配數(shù)組的某一個(gè)下標(biāo)位置的元素,那么我們需要使用上面一開(kāi)始提到的,使用類(lèi)似匹配子Document的那種成員引用(點(diǎn)符號(hào))方式來(lái)構(gòu)造過(guò)濾條件:
db.post.find({"comments.0": "comment two"})
查詢(xún)到的結(jié)果如下:
這里,我們使用{“comments.0”: “comment two”}的方式指定匹配的條件是:數(shù)組”comments”下標(biāo)為0的位置的值為”comment two”。這樣,就可以過(guò)濾掉之前下標(biāo)為1的位置為”comment two”的記錄了。可以看出,在使用數(shù)組下標(biāo)構(gòu)造過(guò)濾條件的時(shí)候,下標(biāo)是從0開(kāi)始的。
MongoDB提供了豐富的操作符來(lái)支持構(gòu)造靈活的過(guò)濾條件,這里就先介紹這么點(diǎn)。由于篇幅關(guān)系,這里就不再展開(kāi)了,下次獨(dú)立寫(xiě)篇文章重點(diǎn)介紹下MongoDB中的查詢(xún)操作。接下來(lái),我們?cè)摽聪氯绾卧贛ongoDB中進(jìn)行更新操作。
UPDATE操作
MongoDB也支持基本的更新操作,它提供了4個(gè)用于更新的方法:
-
db.collection.updateOne()
3.2版本新增
-
db.collection.updateMany()
3.2版本新增
-
db.collection.update()
-
db.collection.replaceOne()
3.2版本新增
這些Update方法支持三個(gè)參數(shù):
-
用于篩選記錄的過(guò)濾條件,過(guò)濾出需要被更新的記錄,過(guò)濾條件和query中使用的過(guò)濾條件類(lèi)似。
-
一個(gè)新的Document,用于更新部分值或者替換除了”_id”之外的一整個(gè)Document。
-
一個(gè)以Document格式組織的一組更新選項(xiàng)。
MongoDB對(duì)于單個(gè)Document的更新操作是原子的。 MongoDB在更新時(shí)對(duì)于”*id”主鍵的處理原則是,不管是更新還是替換Document,都不能更改被更新的Document的”*id”主鍵,如果在替換的時(shí)候包含了不同的”_id”,那么替換會(huì)失敗,如:
上面的例子中,我們修改了原先的”*id”值為1,然后進(jìn)行替換更新,發(fā)現(xiàn)更新失敗,提示”*id”值不能被更改。
當(dāng)我們更新的時(shí)候,新的Document的大小超過(guò)了原先舊的Document的大小的時(shí)候,更新操作會(huì)重新申請(qǐng)一塊更大的空間來(lái)存放這個(gè)新的Document。
接下來(lái),我們來(lái)看下這些更新API的用法。
db.collection.updateOne()
updateOne()函數(shù)是在3.2版本中新增的一個(gè)API,用于更新一條匹配到的Document?,F(xiàn)在我們需要更新我們的Post集合中的標(biāo)題為”First Post”的Document,我們想增加一些評(píng)論,我們可以這么構(gòu)造我們的更新表達(dá)式:
db.post.updateOne({"title": "First Post"}, {"$set": {"comments": ["comment one"]}})
現(xiàn)在,我們的”First Post”這篇文章就有了一條評(píng)論了。這里我們使用”$set”操作符來(lái)設(shè)置一個(gè)新的字段,MongoDB的更新操作提供了一些有用的操作符來(lái)幫助構(gòu)造更新語(yǔ)句。updateOne()函數(shù)會(huì)更新第一個(gè)被匹配到的Document。如果要更新多個(gè)Document,我們可以用updateMany()函數(shù)來(lái)支持。
db.collection.updateMany()
updateMany()函數(shù)可以對(duì)匹配到的所有的Document進(jìn)行更新操作。比如我們想更新所有的文章,讓每篇文章都有一個(gè)瀏覽數(shù)的字段,表示別瀏覽的次數(shù)。我們可以這樣做:
db.post.updateMany({}, {"$set": {"view": 0}})
我們可以看到,通過(guò)updateMany()函數(shù),我們更新了所有的Document,使得每個(gè)Document都包含了一個(gè)”view”字段,初始值為0。
替換Document
上面提到了兩個(gè)API,都是對(duì)Document中的某個(gè)字段進(jìn)行更新。它們除了可以對(duì)Document中的單個(gè)字段進(jìn)行更新外,還可以對(duì)匹配到的整個(gè)Document進(jìn)行替換(除了”*id”屬性外,可以替換任何屬性)。只要把更新參數(shù)改成一個(gè)普通的Document(Document的結(jié)構(gòu)中不包含操作符),就可以對(duì)匹配到的Document替換成參數(shù)中的Document。進(jìn)行Document替換更新的時(shí)候,需要注意:原先的Document中的”*id”屬性是不能被更改的,所以新的用于替換的Document不能包含”*id”屬性,如果包含了”*id”屬性,那么這個(gè)”*id”屬性必須是和被更新的Document的”*id”屬性是相同的。
除了上面的兩個(gè)API可以用于替換Document,MongoDB在3.2版本中新增了一個(gè)replaceOne()函數(shù)來(lái)進(jìn)行替換操作?,F(xiàn)在我們用replaceOne()來(lái)替換一個(gè)Document,我們把”title”是”First Post”的Document替換成新的Document:
db.post.replaceOne({"title": "First Post"}, {"title": "New Post", "content": "new content", "create_time": new Date()})
現(xiàn)在,我們已經(jīng)把”title”為”First Post”的Document替換為了新的”title”為”New Post”的Document了。
最后,我們來(lái)看下上面三個(gè)API的集大成者,就是update()函數(shù),它基本包含了上面提到的三個(gè)API的所有功能,默認(rèn)情況下,update()函數(shù)會(huì)更新匹配到的第一個(gè)Document,如果設(shè)置了”multi”選項(xiàng),那么就可以更新匹配到的所有的Document。
下面我們使用update()來(lái)更新匹配到的第一個(gè)Document:
db.post.update({"title": "New Post"}, {"$set": {"view": 0}})
好了,更新操作介紹到這里,接下來(lái)就是最后一個(gè)刪除操作了。
DELETE操作
到這里,我想大家都已經(jīng)了解了MongoDB中的”增”,”改”,”查”的功能了,接下來(lái)我們來(lái)看下”刪”這個(gè)功能。MongoDB提供了三個(gè)用于刪除操作的API,分別是:
-
db.collection.deleteOne()
-
db.collection.deleteMany()
3.2版本新增
-
db.collection.remove()
3.2版本新增
這三個(gè)API都支持一個(gè)過(guò)濾條件參數(shù),用于匹配到滿(mǎn)足條件的Document,然后進(jìn)行刪除操作。
從三個(gè)API的字面意思我們可以看出,deleteOne()會(huì)刪除匹配到的所有的Document中的第一個(gè),而deleteMany()和remove()會(huì)刪除所有匹配到的Document。
假設(shè)我們需要?jiǎng)h除”title”為”New Post”的Document,我們可以用deleteOne()來(lái)操作
db.post.deleteOne({"title": "New Post"})
當(dāng)刪除了”title”為”New Post”的Document以后,我們?cè)俅稳ゲ樵?xún)的時(shí)候,發(fā)現(xiàn)這個(gè)Document確實(shí)已經(jīng)被刪除了。deleteOne()用于刪除單個(gè)Document,如果我們需要?jiǎng)h除所有滿(mǎn)足過(guò)濾條件的Document的話(huà),我們可以用deleteMany()或者remove()來(lái)實(shí)現(xiàn)。
現(xiàn)在我們想刪除所有瀏覽數(shù)為0的文章,那么我們可以用deleteMany()或者remove來(lái)實(shí)現(xiàn):
db.post.remove({"view": 0})
由于我們存儲(chǔ)在集合中的所有Document的view值都是0,所以上面的操作相當(dāng)于我們清空了我們的Collection。
本文題目:詳解MongoDB中的CRUD操作
地址分享:http://www.dlmjj.cn/article/cdceshc.html


咨詢(xún)
建站咨詢(xún)
