MongoDB【快速入門】

1.MongDB 簡介

MongoDB(來自于英文單詞“Humongous”苟穆,中文含義為“龐大”)是可以應(yīng)用于各種規(guī)模的企業(yè)、各個行業(yè)以及各類應(yīng)用程序的開源數(shù)據(jù)庫诀豁。作為一個適用于敏捷開發(fā)的數(shù)據(jù)庫胎源,MongoDB 的數(shù)據(jù)模式可以隨著應(yīng)用程序的發(fā)展而靈活地更新鲫寄。與此同時耻卡,它也為開發(fā)人員 提供了傳統(tǒng)數(shù)據(jù)庫的功能:二級索引疯汁,完整的查詢系統(tǒng)以及嚴(yán)格一致性等等。 MongoDB 能夠使企業(yè)更加具有敏捷性和可擴展性劲赠,各種規(guī)模的企業(yè)都可以通過使用 MongoDB 來創(chuàng)建新的應(yīng)用,提高與客戶之間的工作效率秸谢,加快產(chǎn)品上市時間凛澎,以及降低企業(yè)成本。

MongoDB 是專為可擴展性估蹄,高性能和高可用性而設(shè)計的數(shù)據(jù)庫塑煎。它可以從單服務(wù)器部署擴展到大型、復(fù)雜的多數(shù)據(jù)中心架構(gòu)臭蚁。利用內(nèi)存計算的優(yōu)勢最铁,MongoDB 能夠提供高性能的數(shù)據(jù)讀寫操作。 MongoDB 的本地復(fù)制和自動故障轉(zhuǎn)移功能使您的應(yīng)用程序具有企業(yè)級的可靠性和操作靈活性垮兑。

以上內(nèi)容摘自官網(wǎng):

1.1 文檔型數(shù)據(jù)庫

簡而言之冷尉,MongoDB是一個免費開源跨平臺的 NoSQL 數(shù)據(jù)庫,與關(guān)系型數(shù)據(jù)庫不同系枪,MongoDB 的數(shù)據(jù)以類似于 JSON 格式的二進(jìn)制文檔存儲:

{
    name: "我沒有三顆心臟",
    age: 22,
}

文檔型的數(shù)據(jù)存儲方式有幾個重要好處:

  1. 文檔的數(shù)據(jù)類型可以對應(yīng)到語言的數(shù)據(jù)類型雀哨,如數(shù)組類型(Array)和對象類型(Object);
  2. 文檔可以嵌套,有時關(guān)系型數(shù)據(jù)庫涉及幾個表的操作雾棺,在 MongoDB 中一次就能完成膊夹,可以減少昂貴的連接花銷;
  3. 文檔不對數(shù)據(jù)結(jié)構(gòu)加以限制捌浩,不同的數(shù)據(jù)結(jié)構(gòu)可以存儲在同一張表放刨;
  4. MongoDB 的文檔數(shù)據(jù)模型和索引系統(tǒng)能有效提升數(shù)據(jù)庫性能;
  5. 復(fù)制集功能提供數(shù)據(jù)冗余尸饺,自動化容災(zāi)容錯进统,提升數(shù)據(jù)庫可用性;
  6. 分片技術(shù)能夠分散單服務(wù)器的讀寫壓力侵佃,提高并發(fā)能力麻昼,提升數(shù)據(jù)庫的可拓展性;
  7. MongoDB 高性能馋辈,高可用性抚芦、可擴展性等特點,使其至 2009 年發(fā)布以來迈螟,逐漸被認(rèn)可叉抡,并被越來越多的用于生產(chǎn)環(huán)境中。AWS答毫、GCP褥民、阿里云等云平臺都提供了十分便捷的 MongoDB 云服務(wù)。

1.2 MongoDB 基礎(chǔ)概念

可以使用我們熟悉的 MySQL 數(shù)據(jù)庫來加以對比:

MySQL 基礎(chǔ)概念 MongoDB 對應(yīng)概念
數(shù)據(jù)庫(database) 容器(database)
表(table) 集合(collection)
行(row) 文檔(document)
列(column) 域(filed)
索引(index) 索引(index)

也借用一下菜鳥教程的圖來更加形象生動的說明一下:

這很容易理解洗搂,但是問題在于:我們?yōu)槭裁匆胄碌母拍钅兀?/strong>(也就是為什么我們要把“表”替換成“集合”消返,“行”替換成“文檔”,“列”替換成“域”呢耘拇?)原因在于撵颊,其實在 MySQL 這樣的典型關(guān)系型數(shù)據(jù)中,我們是在定義表的時候定義列的惫叛,但是由于上述文檔型數(shù)據(jù)庫的特點倡勇,它允許文檔的數(shù)據(jù)類型可以對應(yīng)到語言的數(shù)據(jù)類型,所以我們是在定義文檔的時候才會定義域的嘉涌。

也就是說妻熊,集合中的每個文檔都可以有獨立的域。因此仑最,雖說集合相對于表來說是一個簡化了的容器扔役,而文檔則包含了比行要多得多的信息。

2 搭建環(huán)境

怎么樣都好警医,搭建好環(huán)境就行厅目,這里以 OS 環(huán)境為例,你可以使用 OSX 的 brew 安裝 mongodb:

brew install mongodb

在運行之前我們需要創(chuàng)建一個數(shù)據(jù)庫存儲目錄 /data/db

sudo mkdir -p /data/db

然后啟動 mongodb,默認(rèn)數(shù)據(jù)庫目錄即為 /data/db(如果不是损敷,可以使用 --dbpath 指令來指定):

sudo mongd

過一會兒你就能看到你的 mongodb 運行起來的提示:

具體的搭建過程可以參考菜鳥的教程:http://www.runoob.com/mongodb/mongodb-window-install.html

3 基于 Shell 的 CRUD

3.1 連接實例

通過上面的步驟我們在系統(tǒng)里運行了一個 mongodb 實例葫笼,接下來通過 mongo 命令來連接它:

mongo [options] [db address] [file names]

由于上面運行的 mongodb 運行在 27017 端口,并且滅有啟動安全模式拗馒,所以我們也不需要輸入用戶名和密碼就可以直接連接:

mongo 127.0.0.1:27017

或者通過 --host--port 選項指定主機和端口路星。一切順利的話,就進(jìn)入了 mongoDB shell诱桂,shell 會報出一連串權(quán)限警告洋丐,不過不用擔(dān)心,這并不會影響之后的操作挥等。在添加授權(quán)用戶和開啟認(rèn)證后友绝,這些警告會自動消失。

3.2 CRUD 操作

在進(jìn)行增刪改查操作之前肝劲,我們需要先了解一下常用的 shell 命令:

  • db 顯示當(dāng)前所在數(shù)據(jù)庫迁客,默認(rèn)為 test
  • show dbs 列出可用數(shù)據(jù)庫
  • show tables show collections 列出數(shù)據(jù)庫中可用集合
  • use <database> 用于切換數(shù)據(jù)庫

mongoDB 預(yù)設(shè)有兩個數(shù)據(jù)庫,admin 和 local辞槐,admin 用來存放系統(tǒng)數(shù)據(jù)掷漱,local 用來存放該實例數(shù)據(jù),在副本集中榄檬,一個實例的 local 數(shù)據(jù)庫對于其它實例是不可見的卜范。使用 use 命令切換數(shù)據(jù)庫:

> use admin
> use local
> use newDatabase

可以 use 一個不存在的數(shù)據(jù)庫,當(dāng)你存入新數(shù)據(jù)時鹿榜,mongoDB 會創(chuàng)建這個數(shù)據(jù)庫:

> use newDatabase
> db.newCollection.insert({x:1})
WriteResult({ "nInserted" : 1 })

以上命令向數(shù)據(jù)庫中插入一個文檔海雪,返回 1 表示插入成功,mongoDB 自動創(chuàng)建 newCollection 集合和數(shù)據(jù)庫 newDatabase舱殿。下面將對增查改刪操作進(jìn)行一個簡單的演示奥裸。

3.2.1 創(chuàng)建(Create)

MongoDB 提供 insert 方法創(chuàng)建新文檔:

  • db.collection.inserOne() 插入單個文檔
    WriteResult({ "nInserted" : 1 })
  • db.collection.inserMany() 插入多個文檔
  • db.collection.insert() 插入單條或多條文檔

我們接著在剛才新創(chuàng)建的 newDatabase 下面新增數(shù)據(jù)吧:

db.newCollection.insert({name:"wmyskxz",age:22})

根據(jù)以往經(jīng)驗應(yīng)該會覺得蠻奇怪的,因為之前在這個集合中插入的數(shù)據(jù)格式是 {x:1} 的怀薛,而這里新增的數(shù)據(jù)格式確是 {name:"wmyskxz",age:22} 這個樣子的刺彩。還記得嗎迷郑,文檔型數(shù)據(jù)庫的與傳統(tǒng)型的關(guān)系型數(shù)據(jù)的區(qū)別就是在這里枝恋!

并且要注意,age:22age:"22" 是不一樣的哦嗡害,前者插入的是一個數(shù)值焚碌,而后者是字符串,我們可以通過 db.newCollection.find() 命令查看到剛剛插入的文檔:

> db.newCollection.find()
{ "_id" : ObjectId("5cc1026533907ae66490e46c"), "x" : 1 }
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "name" : "wmyskxz", "age" : 22 }

這里有一個神奇的返回霸妹,那就是多了一個叫做 _id 的東西十电,這是 MongoDB 為你自動添加的字段,你也可以自己生成。大部分情況下還是會讓 MongoDB 為我們生成鹃骂,而且默認(rèn)情況下台盯,該字段是被加上了索引的。

3.2.2 查找(Read)

MongoDB 提供 find 方法查找文檔畏线,第一個參數(shù)為查詢條件:

> db.newCollection.find() # 查找所有文檔
{ "_id" : ObjectId("5cc1026533907ae66490e46c"), "x" : 1 }
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "name" : "wmyskxz", "age" : 22 }
> db.newCollection.find({name:"wmyskxz"}) # 查找 name 為 wmyskxz 的文檔
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "name" : "wmyskxz", "age" : 22 }
> db.newCollection.find({age:{$gt:20}}) # 查找 age 大于 20 的文檔
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "name" : "wmyskxz", "age" : 22 }

上述代碼中的$gt對應(yīng)于大于號>的轉(zhuǎn)義静盅。

第二個參數(shù)可以傳入投影文檔映射數(shù)據(jù):

> db.newCollection.find({age:{$gt:20}},{name:1})
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "name" : "wmyskxz" }

上述命令將查找 age 大于 20 的文檔,返回 name 字段寝殴,排除其他字段蒿叠。投影文檔中字段為 1 或其他真值表示包含,0 或假值表示排除蚣常,可以設(shè)置多個字段位為 1 或 0市咽,但不能混合使用。

為了測試抵蚊,我們?yōu)檫@個集合弄了一些奇奇怪怪的數(shù)據(jù):

> db.newCollection.find()
{ "_id" : ObjectId("5cc1026533907ae66490e46c"), "x" : 1 }
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "name" : "wmyskxz", "age" : 22 }
{ "_id" : ObjectId("5cc108fb33907ae66490e46e"), "name" : "wmyskxz-test", "age" : 22, "x" : 1, "y" : 30 }

然后再來測試:

> db.newCollection.find({age:{$gt:20}},{name:1,x:1}) 
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "name" : "wmyskxz" }
{ "_id" : ObjectId("5cc108fb33907ae66490e46e"), "name" : "wmyskxz-test", "x" : 1 }
> db.newCollection.find({age:{$gt:20}},{name:0,x:0}) 
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "age" : 22 }
{ "_id" : ObjectId("5cc108fb33907ae66490e46e"), "age" : 22, "y" : 30 }
> db.newCollection.find({age:{$gt:20}},{name:0,x:1})
Error: error: {
    "ok" : 0,
    "errmsg" : "Projection cannot have a mix of inclusion and exclusion.",
    "code" : 2,
    "codeName" : "BadValue"
}

從上面的命令我們就可以把我們的一些想法和上面的結(jié)論得以驗證施绎,perfect!

除此之外泌射,還可以通過 count粘姜、skiplimit 等指針(Cursor)方法熔酷,改變文檔查詢的執(zhí)行方式:

> db.newCollection.find().count()
3
> db.newCollection.find().skip(1).limit(10).sort({age:1})
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "name" : "wmyskxz", "age" : 22 }
{ "_id" : ObjectId("5cc108fb33907ae66490e46e"), "name" : "wmyskxz-test", "age" : 22, "x" : 1, "y" : 30 }

上述查找命令跳過 1 個文檔孤紧,限制輸出 10 個,以 age 子段正序排序(大于 0 為正序拒秘,小于 0 位反序)輸出結(jié)果号显。最后,可以使用 Cursor 方法中的 pretty 方法躺酒,提升查詢文檔的易讀性押蚤,特別是在查看嵌套的文檔和配置文件的時候:

> db.newCollection.find().pretty()
{ "_id" : ObjectId("5cc1026533907ae66490e46c"), "x" : 1 }
{
    "_id" : ObjectId("5cc102fb33907ae66490e46d"),
    "name" : "wmyskxz",
    "age" : 22
}
{
    "_id" : ObjectId("5cc108fb33907ae66490e46e"),
    "name" : "wmyskxz-test",
    "age" : 22,
    "x" : 1,
    "y" : 30
}

3.2.3 更新(Update)

MongoDB 提供 update 方法更新文檔:

  • db.collection.updateOne() 更新最多一個符合條件的文檔
  • db.collection.updateMany() 更新所有符合條件的文檔
  • db.collection.replaceOne() 替代最多一個符合條件的文檔
  • db.collection.update() 默認(rèn)更新一個文檔,可配置 multi 參數(shù)羹应,跟新多個文檔

update() 方法為例揽碘。其格式:

> db.collection.update(
    <query>,
    <update>,
    {
        upsert: <boolean>,
        multi: <boolean>
    }
)

各參數(shù)意義:

  • query 為查詢條件
  • update 為修改的文檔
  • upsert 為真,查詢?yōu)榭諘r插入文檔
  • multi 為真园匹,更新所有符合條件的文檔

下面我們測試把 name 字段為 wmyskxz 的文檔更新一下試試:

> db.newCollection.update({name:"wmyskxz"},{name:"wmyskxz",age:30})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

要注意的是雳刺,如果更新文檔只傳入 age 字段,那么文檔會被更新為{age: 30}裸违,而不是{name:"wmyskxz", age:30}掖桦。要避免文檔被覆蓋,需要用到 $set 指令供汛,$set 僅替換或添加指定字段:

> db.newCollection.update({name:"wmyskxz"},{$set:{age:30}})

如果要在查詢的文檔不存在的時候插入文檔枪汪,要把 upsert 參數(shù)設(shè)置真值:

> db.newCollection.update({name:"wmyskxz11"},{$set:{age:30}},{upsert:true})

update 方法默認(rèn)情況只更新一個文檔涌穆,如果要更新符合條件的所有文檔,要把 multi 設(shè)為真值雀久,并使用 $set 指令:

> db.newCollection.update({age:{$gt:20}},{$set:{test:"A"}},{multi:true})
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
> db.newCollection.find()
{ "_id" : ObjectId("5cc1026533907ae66490e46c"), "x" : 1 }
{ "_id" : ObjectId("5cc102fb33907ae66490e46d"), "name" : "wmyskxz", "age" : 30, "test" : "A" }
{ "_id" : ObjectId("5cc108fb33907ae66490e46e"), "name" : "wmyskxz-test", "age" : 22, "x" : 1, "y" : 30, "test" : "A" }
{ "_id" : ObjectId("5cc110148d0a578f03d43e81"), "name" : "wmyskxz11", "age" : 30, "test" : "A" }

3.2.4 刪除(Delete)

MongoDB 提供了 delete 方法刪除文檔:

  • db.collection.deleteOne() 刪除最多一個符合條件的文檔
  • db.collection.deleteMany() 刪除所有符合條件的文檔
  • db.collection.remove() 刪除一個或多個文檔

以 remove 方法為例:

> db.newCollection.remove({name:"wmyskxz11"})
> db.newCollection.remove({age:{$gt:20}},{justOne:true})
> db.newCollection.find()
{ "_id" : ObjectId("5cc1026533907ae66490e46c"), "x" : 1 }
{ "_id" : ObjectId("5cc108fb33907ae66490e46e"), "name" : "wmyskxz-test", "age" : 22, "x" : 1, "y" : 30, "test" : "A" }

MongoDB 提供了 drop 方法刪除集合宿稀,返回 true 表面刪除集合成功:

> db.newCollection.drop()

3.2.5 小結(jié)

相比傳統(tǒng)關(guān)系型數(shù)據(jù)庫,MongoDB 的 CURD 操作更像是編寫程序赖捌,更符合開發(fā)人員的直覺原叮,不過 MongoDB 同樣也支持 SQL 語言。MongoDB 的 CURD 引擎配合索引技術(shù)巡蘸、數(shù)據(jù)聚合技術(shù)和 JavaScript 引擎奋隶,賦予 MongoDB 用戶更強大的操縱數(shù)據(jù)的能力。

參考文章:簡明 MongoDB 入門教程 - https://segmentfault.com/a/1190000010556670

4 MongoDB 數(shù)據(jù)模型的一些討論

前置申明:這一部分基于以下鏈接整理 https://github.com/justinyhuang/the-little-mongodb-book-cn/blob/master/mongodb.md#%E8%AE%B8%E5%8F%AF%E8%AF%81

這是一個抽象的話題悦荒,與大多數(shù)NoSQL方案相比,在建模方面,面向文檔的數(shù)據(jù)庫算是和關(guān)系數(shù)據(jù)庫相差最小的唯欣。這些差別是很小,但是并不是說不重要搬味。

4.1 沒有連接(Join)

您要接受的第一個也是最基本的一個差別境氢,就是 MongoDB 沒有連接(join)。我不知道MongoDB不支持某些類型連接句法的具體原因碰纬,但是我知道一般而言人們認(rèn)為連接是不可擴展的萍聊。也就是說,一旦開始橫向分割數(shù)據(jù)悦析,最終不可避免的就是在客戶端(應(yīng)用程序服務(wù)器)使用連接寿桨。且不論MongoDB為什么不支持連接,事實是數(shù)據(jù)是有關(guān)系的强戴,可是MongoDB不支持連接亭螟。(譯者:這里的關(guān)系指的是不同的數(shù)據(jù)之間是有關(guān)聯(lián)的,對于沒有關(guān)系的數(shù)據(jù)骑歹,就完全不需要連接预烙。)

為了在沒有連接的MongoDB中生存下去,在沒有其他幫助的情況下道媚,我們必須在自己的應(yīng)用程序中實現(xiàn)連接扁掸。

基本上我們需要用第二次查詢去找到相關(guān)的數(shù)據(jù)。找到并組織這些數(shù)據(jù)相當(dāng)于在關(guān)系數(shù)據(jù)庫中聲明一個外來的鍵∽钣颍現(xiàn)在先別管什么獨角獸了谴分,我們來看看我們的員工。首先我們創(chuàng)建一個員工的數(shù)據(jù)(這次我告訴您具體的_id值羡宙,這樣我們的例子就是一樣的了):

db.employees.insert({_id: ObjectId("4d85c7039ab0fd70a117d730"), name: 'Leto'})

然后我們再加入幾個員工并把 Leto 設(shè)成他們的老板:

db.employees.insert({_id: ObjectId("4d85c7039ab0fd70a117d731"), name: 'Duncan', manager: ObjectId("4d85c7039ab0fd70a117d730")});
db.employees.insert({_id: ObjectId("4d85c7039ab0fd70a117d732"), name: 'Moneo', manager: ObjectId("4d85c7039ab0fd70a117d730")});

(有必要再強調(diào)一下狸剃,_id可以是任何的唯一的值掐隐。在實際工作中你很可能會用到ObjectId狗热, 所以我們在這里也使用它)

顯然钞馁,要找到Leto的所有員工,只要執(zhí)行:

db.employees.find({manager: ObjectId("4d85c7039ab0fd70a117d730")})

沒什么了不起的匿刮。在最糟糕的情況下僧凰,為彌補連接的缺失需要做的只是再多查詢一次而已,該查詢很可能是經(jīng)過索引了的熟丸。

4.1.1 數(shù)組和嵌入文檔(Embedded Documents)

MongoDB 沒有連接并不意味著它沒有其他的優(yōu)勢训措。還記得我們曾說過 MongoDB 支持?jǐn)?shù)組并把它當(dāng)成文檔中的一級對象嗎?當(dāng)處理多對一或是多對多關(guān)系的時候光羞,這一特性就顯得非常好用了绩鸣。用一個簡單的例子來說明,如果一個員工有兩個經(jīng)理纱兑,我們可以把這個關(guān)系儲存在一個數(shù)組當(dāng)中:

({name: 'Siona', manager: [ObjectId("4d85c7039ab0fd70a117d730"), ObjectId("4d85c7039ab0fd70a117d732")] })

需要注意的是呀闻,在這種情況下,有些文檔中的 manager 可能是一個向量潜慎,而其他的卻是數(shù)組捡多。在兩種情況下,前面的 find 還是一樣可以工作:

db.employees.find({manager: ObjectId("4d85c7039ab0fd70a117d730")})

很快您就會發(fā)現(xiàn)數(shù)組中的值比起多對多的連接表(join-table)來說要更容易處理铐炫。

除了數(shù)組垒手,MongoDB 還支持嵌入文檔。嘗試插入含有內(nèi)嵌文檔的文檔倒信,像這樣:

db.employees.insert({_id: ObjectId("4d85c7039ab0fd70a117d734"), name: 'Ghanima', family: {mother: 'Chani', father: 'Paul', brother: ObjectId("4d85c7039ab0fd70a117d730")}})

也許您會這樣想科贬,確實也可以這樣做:嵌入文檔可以用‘.’符號來查詢:

db.employees.find({'family.mother': 'Chani'})

就這樣,我們簡要地介紹了嵌入文檔適用的場合以及您應(yīng)該怎樣使用它鳖悠。

4.1.2 DBRef

MongoDB 支持一個叫做 DBRef 的功能唆迁,許多 MongoDB 的驅(qū)動都提供對這一功能的支持。當(dāng)驅(qū)動遇到一個 DBRef 時它會把當(dāng)中引用的文檔讀取出來竞穷。DBRef 包含了所引用的文檔的 ID 和所在的集合唐责。它通常專門用于這樣的場合:相同集合中的文檔需要引用另外一個集合中的不同文檔。例如瘾带,文檔 1 的 DBRef 可能指向 managers 中的文檔鼠哥,而文檔 2 中的 DBRef 可能指向 employees 中的文檔。

4.1.3 范規(guī)范化(Denormalization)

代替連接的另一種方法就是反規(guī)范化數(shù)據(jù)看政。在過去朴恳,反規(guī)范化是為性能敏感代碼所設(shè),或者是需要數(shù)據(jù)快照(例如審計日志)的時候才應(yīng)用的允蚣。然而于颖,隨著NoSQL的日漸普及,有許多這樣的數(shù)據(jù)庫并不提供連接操作嚷兔,于是作為規(guī)范建模的一部分森渐,反規(guī)范化就越來越常見了做入。這樣說并不是說您就需要為每個文檔中的每一條信息創(chuàng)建副本。與此相反同衣,與其在設(shè)計的時候被復(fù)制數(shù)據(jù)的擔(dān)憂牽著走竟块,還不如按照不同的信息應(yīng)該歸屬于相應(yīng)的文檔這一思路來對數(shù)據(jù)建模旧巾。

比如說讲婚,假設(shè)您在編寫一個論壇的應(yīng)用程序。把一個 user 和一篇 post 關(guān)聯(lián)起來的傳統(tǒng)方法是在 posts 中加入一個 userid 的列丁眼。這樣的模型中埠况,如果要顯示 posts 就不得不讀人市(連接)users。一種簡單可行的替代方案就是直接把 nameuserid 存儲在 post 中辕翰。您甚至可以用嵌入文檔來實現(xiàn)违帆,比如說 user: {id: ObjectId('Something'), name: 'Leto'}。當(dāng)然金蜀,如果允許用戶更改他們的用戶名刷后,那么每當(dāng)有用戶名修改的時候,您就需要去更新所有的文檔了(這需要一個額外的查詢)渊抄。

對一些人來說改用這種方法并非易事尝胆。甚至在一些情況下根本行不通。不過別不敢去嘗試這種方法:有時候它不僅可行护桦,而且就是正確的方法含衔。

4.1.4 應(yīng)該選擇哪一種?

當(dāng)處理一對多或是多對多問題的時候二庵,采用id數(shù)組往往都是正確的策略贪染。可以這么說催享,DBRef 并不是那么常用杭隙,雖然您完全可以試著采用這項技術(shù)。這使得新手們在面臨選擇嵌入文檔還是手工引用(manual reference)時猶豫不決因妙。

首先痰憎,要知道目前一個單獨的文檔的大小限制是 4MB,雖然已經(jīng)比較大了攀涵。了解了這個限制可以為如何使用文檔提供一些思路铣耘。目前看來多數(shù)的開發(fā)者還是大量地依賴手工引用來維護(hù)數(shù)據(jù)的關(guān)系。嵌入文檔經(jīng)常被使用以故,but mostly for small pieces of data which we want to always pull with the parent document蜗细。一個真實的例子,我把 accounts 文檔嵌入存儲在用戶的文檔中怒详,就像這樣:

db.users.insert({name: 'leto', email: 'leto@dune.gov', account: {allowed_gholas: 5, spice_ration: 10}})

這不是說您就應(yīng)該低估嵌入文檔的作用炉媒,也不是說應(yīng)該把它當(dāng)成是鮮少用到的工具并直接忽略踪区。將數(shù)據(jù)模型直接映射到目標(biāo)對象上可以使問題變得更加簡單,也往往因此而不再需要連接操作橱野。當(dāng)您知道 MongoDB 允許對嵌入文檔的域進(jìn)行查詢并做索引后,這個說法就尤其顯得正確了善玫。

4.2 集合:少一些還是多一些水援?

既然集合不強制使用模式,那么就完全有可能用一個單一的集合以及一個不匹配的文檔構(gòu)建一個系統(tǒng)茅郎。以我所見過的情況蜗元,大部分的 MongoDB 系統(tǒng)都像您在關(guān)系數(shù)據(jù)庫中所見到的那樣布局。換句話說系冗,如果在關(guān)系數(shù)據(jù)庫中會用表奕扣,那么很有可能在 MongoDB 中就要用集合(多對多連接表在這里是一個不可忽視的例外)

當(dāng)把嵌入文檔引進(jìn)來的時候,討論就會變得更加有意思了掌敬。最常見的例子就是博客系統(tǒng)惯豆。是應(yīng)該分別維護(hù) postscomments 兩個集合,還是在每個 post 中嵌入一個 comments 數(shù)組奔害?暫且不考慮那個 4MB 的限制(哈姆雷特所有的評論也不超過200KB楷兽,誰的博客會比他更受歡迎?)华临,大多數(shù)的開發(fā)者還是傾向于把數(shù)據(jù)劃分開芯杀。因為這樣既簡潔又明確。

沒有什么硬性的規(guī)定(呃雅潭,除了 4MB 的限制)揭厚。做了不同的嘗試之后您就可以憑感覺知道怎樣做是對的了。

總結(jié)

至此已經(jīng)對 MongoDB 有了一個基本的了解和入門扶供,但是要運用在實際的項目中仍然有許多實踐需要自己去完成


按照慣例黏一個尾巴:

歡迎轉(zhuǎn)載筛圆,轉(zhuǎn)載請注明出處!
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關(guān)注公眾微信號:wmyskxz
分享自己的學(xué)習(xí) & 學(xué)習(xí)資料 & 生活
想要交流的朋友也可以加qq群:3382693

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末椿浓,一起剝皮案震驚了整個濱河市顽染,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌轰绵,老刑警劉巖粉寞,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異左腔,居然都是意外死亡唧垦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門液样,熙熙樓的掌柜王于貴愁眉苦臉地迎上來振亮,“玉大人巧还,你說我怎么就攤上這事》唤眨” “怎么了麸祷?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長褒搔。 經(jīng)常有香客問我阶牍,道長,這世上最難降的妖魔是什么星瘾? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任走孽,我火速辦了婚禮,結(jié)果婚禮上琳状,老公的妹妹穿的比我還像新娘磕瓷。我一直安慰自己,他們只是感情好念逞,可當(dāng)我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布困食。 她就那樣靜靜地躺著,像睡著了一般翎承。 火紅的嫁衣襯著肌膚如雪陷舅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天审洞,我揣著相機與錄音莱睁,去河邊找鬼。 笑死芒澜,一個胖子當(dāng)著我的面吹牛仰剿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播痴晦,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼南吮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了誊酌?” 一聲冷哼從身側(cè)響起部凑,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎碧浊,沒想到半個月后涂邀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡箱锐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年比勉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡浩聋,死狀恐怖观蜗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衣洁,我是刑警寧澤墓捻,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站坊夫,受9級特大地震影響砖第,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜践樱,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一厂画、第九天 我趴在偏房一處隱蔽的房頂上張望凸丸。 院中可真熱鬧拷邢,春花似錦、人聲如沸屎慢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腻惠。三九已至环肘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間集灌,已是汗流浹背悔雹。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留欣喧,地道東北人腌零。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像唆阿,于是被迫代替她去往敵國和親益涧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 一驯鳖、MongoDB簡介 1.概述 ? MongoDB是一個基于分布式文件存儲的數(shù)據(jù)庫闲询,由C++語言編寫。旨在為WE...
    鄭元吉閱讀 977評論 0 2
  • 一浅辙、NoSQL概述 NoSQL是Not Only SQL的縮寫扭弧,指的是非關(guān)系型數(shù)據(jù)庫,與傳統(tǒng)的關(guān)系型數(shù)據(jù)庫相對應(yīng)记舆,...
    凜_冬_將_至閱讀 2,101評論 0 4
  • mongodb介紹 MongoDB是一個高性能寄狼,開源,無模式的文檔型數(shù)據(jù)庫,是當(dāng)前NoSql數(shù)據(jù)庫中比較熱門的一種...
    測試幫日記閱讀 441評論 0 1
  • MongoDB 數(shù)據(jù)庫 -> 集合 -> 文檔database -> collections -> documen...
    Yangkeloff閱讀 1,100評論 0 0
  • 跑了兩天終于把護(hù)照拿到了手泊愧,過程是我已經(jīng)預(yù)料到的伊磺,依然很艱難,也就不想多說覺得沒有意義删咱,也算了了心頭一件大事屑埋,吃完...
    忍不住想念_e70c閱讀 740評論 0 0