<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          MongoDB 極簡入門實踐

          共 18567字,需瀏覽 38分鐘

           ·

          2021-03-17 09:26

          公眾號關(guān)注“杰哥的IT之旅”,
          選擇“星標(biāo)”,重磅干貨,第一時間送達(dá)!

          1. 為什么用 MongoDB?


          傳統(tǒng)的計算機(jī)應(yīng)用大多使用關(guān)系型數(shù)據(jù)庫來存儲數(shù)據(jù),比如大家可能熟悉的 MySQL、Sqlite 等等,它的特點是數(shù)據(jù)以表(table)的形式儲存起來的。數(shù)據(jù)庫由一張張排列整齊的表格構(gòu)成,就好像一個 Excel 表單一樣,每個表格會有若干列,比如一個學(xué)生信息表,可能包含學(xué)號、姓名、性別、入學(xué)年份、高考成績、籍貫等等。而表格的每一排,則是一個個學(xué)生的具體信息。在企業(yè)級應(yīng)用和前互聯(lián)網(wǎng)時代,關(guān)系型數(shù)據(jù)庫幾乎是不二選擇。關(guān)系型數(shù)據(jù)庫的特點是有整齊劃一的組織,很方便對數(shù)據(jù)進(jìn)行描述、插入、搜索。

          想象有一個傳統(tǒng)的網(wǎng)上服裝商店吧,它的主要的數(shù)據(jù)可能是儲存在一張叫 products 的表單里,表單可能包含這些列:商品編號(ID)、名稱(Name)、商家(brand)、主目錄(cate)、子目錄(sub-cat)、零售價(price)、是否促銷(promotion)等等。如果有一個用戶想要查找所有價格低于 300 元的正在促銷的鞋子的編號和名稱,則可以執(zhí)行類似于以下的 SQL 語句:

          SELECT IDname 
          FROM products 
          WHERE cate='shoes' 
          AND price<300 and 
          AND promotion=true;

          SQL 具備了強(qiáng)大了的深度查詢能力,能滿足各式各樣的查詢要求。而如果要對數(shù)據(jù)進(jìn)行添加和刪除,成本也是非常低的。這些是 SQL 的優(yōu)勢之一, 但隨著互聯(lián)網(wǎng)的興起以及數(shù)據(jù)形式的多樣化,四平八穩(wěn)的 SQL 表單在一些領(lǐng)域漸漸顯現(xiàn)出它的劣勢。讓我們通過一個例子來說明??紤]一個博客后臺系統(tǒng),如果我們用關(guān)系型數(shù)據(jù)庫為每篇博客(article)建一個表單的話,這個表單大概會包括以下這些列:

          IDTitleDescriptionAuthorContentLikes
          A_1Title1Political ArticleJoeContent 112
          A_2Title2Humorous StorySamContent 250

          這時候用 SQL 數(shù)據(jù)庫來存儲是非常方便的,但假如我們要為每篇文章添加評論功能,會發(fā)現(xiàn)每篇文章可能要多篇評論,而且這個數(shù)目是動態(tài)變化的,而且每篇評論還包括好幾項內(nèi)容:評論的人、評論的時間、以及評論內(nèi)容。這時候要將這些內(nèi)容都塞進(jìn)上述的那個表,就顯得很困難。通常的做法是為評論(comment)單獨建一個表:

          IDAuthorTimeContentArticle
          C_1Anna2014-12-26 08:23Really good articles!A_1
          C_2David2014-12-25 09:30I like it!A_1

          類似地,每篇文章可能會有若干標(biāo)簽(tags)。標(biāo)簽本身又是一個表單:

          IDCategoryTagsContentArticle
          T_1Anna2014-12-26 08:23Really good articles!A_1
          T_2David2014-12-25 09:30I like it!A_2

          而博客的表格則要通過 foreign key 跟這些相關(guān)聯(lián)的表格聯(lián)系起來(可能還包括作者、出版社等其它表格)。這樣一來,當(dāng)我們做查詢的時候,比如說,“找出評論數(shù)不少于 3 的標(biāo)簽為‘政治評論’的作者為 Sam 的文章”,就會涉及到復(fù)雜的跨表查詢,需要大量使用 join 語句。這種跨表查詢不僅降低了查詢速度,而且這些語句寫起來也不簡單。

          那么,如果用 MongoDB 數(shù)據(jù)庫來實現(xiàn),可以如何設(shè)計數(shù)據(jù)模型呢?很簡單,像下面這樣:

           _id: POST_ID
             title: TITLE_OF_POST, 
             description: POST_DESCRIPTION,
             author: POST_BY,
             tags: [TAG1, TAG2, TAG3],
             likes: TOTAL_LIKES, 
             comments: [ 
                {
                   user:'COMMENT_BY',
                   message: TEXT,
                   dateCreated: DATE_TIME,
                },
                {
                   user:'COMMENT_BY',
                   message: TEXT,
                   dateCreated: DATE_TIME,
                }
             ]

          在 MongoDB 里,每篇博客文章以一個文檔(document)的形式保存起來,而文檔內(nèi)部包含了很多項目,比如 title tags 等,每一個項目都是 key-value 的形式,即有一個項目的名字,比如title ,以及它的值 TITLE_OF_POST。而重要的是,一個 key 可以有多個 values ,他們用 [] 括起來。

          這種“寬松”的數(shù)據(jù)存儲形式非常靈活,MongoDB 不限制每個 key 對應(yīng)的 values 的數(shù)目。比如有的文章沒有評論,則它的值就是一個空集,完全沒有問題;有的文章評論很多,也可以無限制地插入。更靈活的是,MongoDB 不要求同一個集合(collection 相當(dāng)于 SQL 的 table)里面的不同 document 有相同的 key,比如除了上述這種文檔組織,有的文檔所代表的文章可能沒有 likes 這個項目,再比如有的文章可能有更多的項目,比如可能還有 dislikes 等等。這些不同的文檔都可以靈活地存儲在同一個集合下,而且查詢起來也異常簡單,因為都在一個文檔里,不用進(jìn)行各種跨文檔查詢。而這種 MongoDB 式的存儲也方便了數(shù)據(jù)的維護(hù),對于一篇博客文章來說,所有的相關(guān)數(shù)據(jù)都在這個 document 里面,不用去考慮一個數(shù)據(jù)操作需要 involve 多少個表格。

          當(dāng)然,除了上述的優(yōu)點,MongoDB 還有不少別的優(yōu)勢,比如 MongoDB 的數(shù)據(jù)是用 JSON(JavaScript Object Notation)存儲的(就是上面的這種 key-value 的形式),適用于而幾乎所有的 Web 應(yīng)用,存儲的數(shù)據(jù)和應(yīng)用的數(shù)據(jù)的格式是高度一致的,不需經(jīng)過轉(zhuǎn)換。

          2. 關(guān)于這篇文章

          這個極簡教程,或者說筆記,并不是一個覆蓋 MongoDB 方方面面的教程。所謂極簡的意思,就是只選取那些最重要、最常用的內(nèi)容進(jìn)行基于實例的介紹,從而讓讀者能夠在最短的時間內(nèi)快速上手,并且能順利地進(jìn)行后續(xù)的縱深的學(xué)習(xí)。

          具體地說,這個教程的特點是:

          • 不求全面,只求實用。只覆蓋最核心的部分;

          • 以大量例子為導(dǎo)向;

          • 一邊閱讀一邊動手操作的話,大約只需要 2 小時的時間;

          閱讀這篇文章不需要有特別的基礎(chǔ),但最好知道數(shù)據(jù)庫的基本概念,如果本身熟悉 SQL 那就更好啦。

          3. 安裝與環(huán)境

          3.1 使用 MongoDB Atlas + Compass(推薦)

          MongoDB 提供了一個叫做 Atlas 的云服務(wù),可以直接在云上架設(shè) Server,然后我們可以在本地遠(yuǎn)程連接 Server。這樣做的好處是,用戶不必下載、安裝和架設(shè)本地的 MongoDB 服務(wù)器。對于初學(xué)者而言,這個方式要更簡單,可以最大程度地避免安裝過程中的各種坑。

          簡單步驟如下:

          • 1. Start Mongo Atlas:https://www.mongodb.com/cloud/atlas,基本上按默認(rèn)設(shè)置走即可

          • 2. 設(shè)置完畢后,點擊 connect,并點選通過 MongoDB Compass 連接服務(wù)器。按提示下載 Compass

          • 3. 用之前 Atlas 里面設(shè)置的賬號密碼登錄 Compass,然后點擊左下角的 MongoSH Beta,就可以輸入命令行了

          3.2 本地架設(shè) server

          MongoDB 可以在 Windows、Linux、Mac OS X 等主流平臺運行,而且下載和安裝非常簡單,非常友好。這篇文檔的例子采用 MongoDB 2.6 版本,均在 OS X 測試過,有充足的理由相信,在其它平臺也能順利運行。

          Windows的安裝和設(shè)置可以參考:http://www.w3cschool.cc/mongodb/mongodb-window-install.html;

          Linux的安裝和設(shè)置可以參考:http://www.w3cschool.cc/mongodb/mongodb-linux-install.html;

          Mac OS X 下的安裝和設(shè)置:

          • 1. 在 https://www.mongodb.org/ 下載適合你的 Mac 的 MongoDb;

          • 2. 下載得到的文件是一個 zip 文件,解壓,然后放到你想到的文件夾,比如 /Users/Steven/MongoDB;

          • 3. 創(chuàng)建一個你喜歡的文件夾來存儲你的數(shù)據(jù),比如 /User/Steven/myData;

          • 4. 打開 Terminal,cd 到 2 里面那個文件夾 /Users/Steven/MongoDB,再 cd bin;

          • 5. 輸入 ./mongod --dbpath /User/Steven/myData,等到出現(xiàn)類似“waiting for connections on port 27017”,說明MongoDB服務(wù)器已架設(shè)好,而數(shù)據(jù)將儲存在 myData 里面;

          • 6. 新打開一個 Terminal,cd /Users/Steven/MongoDB/bin,然后運行 ./mongo; 順利的話它將出現(xiàn)一個 interactive shell 讓你進(jìn)行各種操作,而你的數(shù)據(jù)將儲存在 myData 里

          如果以上的各個步驟都運行順利,就可以跳到下一節(jié)啦。

          4. 創(chuàng)建集合和刪除集合

          在上一節(jié)執(zhí)行完步驟 6 后,你會看到命令行里顯示:connecting to: test,這里的 test 是默認(rèn)的數(shù)據(jù)庫。這里我們可以新建一個數(shù)據(jù)庫。在命令行里打入:
          use tutorial

          這樣就新建了一個叫做 tutorial 的數(shù)據(jù)庫。你可以執(zhí)行

          show databases

          來顯示當(dāng)前的數(shù)據(jù)庫。不過這時候由于我們的新數(shù)據(jù)庫是空的,所以會顯示類似這樣的:

          admin  (empty)
          local  0.078GB

          我們試著往我們的數(shù)據(jù)庫里添加一個集合(collection),MongoDB 里的集合和 SQL 里面的表格是類似的:

          db.createCollection('author')

          順利的話會顯示:

          "ok" : 1 }

          表示創(chuàng)建成功。

          你可以再回頭執(zhí)行:

          show databases

          這時候我們的 tutorial 集合已經(jīng)位列其中。你可以再執(zhí)行

          show collections

          可以看到創(chuàng)建的集合 author 也在其中。

          我們暫時不需要 author 這個集合,所以我們可以通過執(zhí)行:

          db.author.drop()

          來將其刪除。這時候你再執(zhí)行 show collections,就再也看不到我們的 author 了。

          這一節(jié)要記住的點主要只有一個:集合(collection)類似于 SQL 的表格(table),類似于 Excel 的一個個表格。

          5. 插入

          想象一個精簡版的“豆瓣電影”。我們需要創(chuàng)建一個數(shù)據(jù)庫,來存儲每部電影的信息,電影的信息包括:

          • 電影名字

          • 導(dǎo)演

          • 主演(可能多個)

          • 類型標(biāo)簽(可能多個)

          • 上映日期

          • 喜歡人數(shù)

          • 不喜歡人數(shù)

          • 用戶評論(可能多個)

          顯然我們需要先創(chuàng)建一個叫電影的集合:

          db.createCollection('movie')

          然后,我們就可以插入數(shù)據(jù)了:

          db.movie.insert(
           {
             title: 'Forrest Gump'
             directed_by: 'Robert Zemeckis',
             stars: ['Tom Hanks''Robin Wright''Gary Sinise'],
             tags: ['drama''romance'],
             debut: new Date("1994-07-06T00:00:00"),
             likes: 864367,
             dislikes: 30127,
             comments: [ 
                {
                   user:'user1',
                   message: 'My first comment',
                   dateCreated: new Date("2020-10-15T00:00:00"),
                   like: 0 
                },
                {
                   user:'user2',
                   message: 'My first comment too!',
                   dateCreated: new Date("2019-04-15T00:00:00"),
                   like: 0 
                }
             ]
          }
          )

          請注意,這里插入數(shù)據(jù)之前,我們并不需要先聲明 movie 這個集合里面有哪些項目。我們直接插入就可以了~這一點和 SQL 不一樣,SQL 必須先聲明一個 table 里面有哪些列,而 MongoDB 不需要。

          把上面的例子復(fù)制進(jìn)命令行應(yīng)該可以順利運行,但我強(qiáng)烈建議你手動打一下,或者輸入一部你自己喜歡的電影。insert 操作有幾點需要注意:

          • 1. 不同 key-value 需要用逗號隔開,而 key:value 中間是用冒號;

          • 2. 如果一個 key 有多個 value,value 要用 []。哪怕當(dāng)前只有一個 value,也加上 [] 以備后續(xù)的添加;

          • 3. 整個“數(shù)據(jù)塊”要用 {} 括起來;

          如果你在 insert 之后看到 WriteResult({ "nInserted" : 1 }),說明寫入成功。

          這個時候你可以用查詢的方式來返回數(shù)據(jù)庫中的數(shù)據(jù):

          db.movie.find().pretty()

          這里 find() 里面是空的,說明我們不做限制和篩選,類似于 SQL 沒有 WHERE 語句一樣。而 pretty() 輸出的是經(jīng)格式美化后的數(shù)據(jù),你可以自己試試沒有 pretty() 會怎么樣。

          仔細(xì)觀察 find() 的結(jié)果,你會發(fā)現(xiàn)多了一個叫 '_id' 的東西,這是數(shù)據(jù)庫自動創(chuàng)建的一個 ID 號,在同一個數(shù)據(jù)庫里,每個文檔的 ID 號都是不同的。

          我們也可以同時輸入多個數(shù)據(jù):

          db.movie.insert([
           {
             title: 'Fight Club'
             directed_by: 'David Fincher',
             stars: ['Brad Pitt''Edward Norton''Helena Bonham Carter'],
             tags: 'drama',
             debut: new Date("1999-10-15T00:00:00"),
             likes: 224360,
             dislikes: 40127,
             comments: [ 
                {
                   user:'user3',
                   message: 'My first comment',
                   dateCreated: new Date("2020-10-15T01:00:00"),
                   like: 0 
                },
                {
                   user:'user2',
                   message: 'My first comment too!',
                   dateCreated: new Date("2020-11-15T01:00:00"),
                   like: 14 
                },
                {
                   user:'user7',
                   message: 'Good Movie!',
                   dateCreated: new Date("2020-10-15T08:00:00"),
                   like: 2
                }
             ]
          },
          {
             title: 'Seven'
             directed_by: 'David Fincher',
             stars: ['Morgan Freeman''Brad Pitt',  'Kevin Spacey'],
             tags: ['drama','mystery','thiller'],
             debut: new Date("1995-10-22T01:00:00"),
             likes: 134370,
             dislikes: 1037,
             comments: [ 
                {
                   user:'user3',
                   message: 'Love Kevin Spacey',
                   dateCreated: new Date("2020-12-15T01:00:00"),
                   like: 0 
                },
                {
                   user:'user2',
                   message: 'Good works!',
                   dateCreated: new Date("2020-10-15T11:22:33"),
                   like: 14 
                },
                {
                   user:'user7',
                   message: 'Good Movie!',
                   dateCreated: new Date("2020-08-15T01:00:00"),
                   like: 2
                }
             ]
          }
          ])

          順利的話會顯示:

          { acknowledged: true,
            insertedIds: 
             { '0': ObjectId("5ffafff5f136fdd9f4ca1492"),
               '1': ObjectId("5ffafff5f136fdd9f4ca1493") } }

          表面我們成功地插入了兩個數(shù)據(jù)。注意批量插入的格式是這樣的:db.movie.insert([{ITEM1},{ITEM2}])。幾部電影的外面需要用 [] 括起來。

          請注意,雖然 collection 的插入不需要先聲明,但表達(dá)相同意思的 key,名字要一樣,比如,如果我們在一個文檔里用 directed_by 來表示導(dǎo)演,則在其它文檔也要保持同樣的名字(而不是 director 之類的)。不同的名字不是不可以,技術(shù)上完全可行,但會給查詢和更新帶來困難。

          好了,到這里,我們就有了一個叫 tutorial 的數(shù)據(jù)庫,里面有一個叫 movie 的集合,而 movie 里面有三個記錄。接下來我們就可以對其進(jìn)行查詢了。

          6. 查詢

          在上一節(jié)我們已經(jīng)接觸到最簡單的查詢 db.movie.find().pretty()。MongoDB 支持各種各樣的深度查詢功能。先來一個最簡單的例子,找出大衛(wèi)芬奇(David Fincher)導(dǎo)演的所有電影:

          db.movie.find({'directed_by':'David Fincher'}).pretty()

          將返回《搏擊俱樂部》和《七宗罪》兩部電影。這種搜索和 SQL 的 WHERE 語句是很相似的。

          也可以設(shè)置多個條件。比如找出大衛(wèi)芬奇導(dǎo)演的, 摩根弗里曼主演的電影:

          db.movie.find({'directed_by':'David Fincher''stars':'Morgan Freeman'}).pretty()

          這里兩個條件之間,是 AND 的關(guān)系,只有同時滿足兩個條件的電影才會被輸出。同理,可以設(shè)置多個的條件,不贅述。

          條件之間也可以是或的關(guān)系,比如找出羅賓懷特或摩根弗里曼主演的電影:

          db.movie.find(
          {
            $or
               [  {'stars':'Robin Wright'}, 
                  {'stars':'Morgan Freeman'}
               ]
          }).pretty()

          注意這里面稍顯復(fù)雜的各種括號。

          還可以設(shè)置一個范圍的搜索,比如找出 50 萬人以上贊的電影:

          db.movie.find({'likes':{$gt:500000}}).pretty()

          同樣要注意略復(fù)雜的括號。注意,在這些查詢里,key 的單引號都是可選的,也就是說,上述語句也可以寫成:

          db.movie.find({likes:{$gt:500000}}).pretty()

          類似地,少于二十萬人贊的電影:

          db.movie.find({likes:{$lt:200000}}).pretty()

          類似的運算符還有:$lte(小于或等于)、$gte(大于或等于)、$ne(不等于)。

          注意,對于包含多個值的 key,同樣可以用 find 來查詢。比如:

          db.movie.find({'tags':'romance'})

          將返回《阿甘正傳》,雖然其標(biāo)簽既有 romance,又有 drama,但只要符合一個就可以了。

          如果你確切地知道返回的結(jié)果只有一個,也可以用 findOne

          db.movie.findOne({'title':'Forrest Gump'})

          如果有多個結(jié)果,則會按磁盤存儲順序返回第一個。請注意,findOne() 自帶 pretty 模式,所以不能再加 pretty(),將報錯。

          如果結(jié)果很多而你只想顯示其中一部分,可以用 limit()skip(),前者指明輸出的個數(shù),后者指明從第二個結(jié)果開始數(shù)。比如:

          db.movie.find().limit(2).skip(1).pretty()

          則跳過第一部,從第二部開始選取兩部電影。

          7. 局部查詢

          第五節(jié)的時候我們講了 find 的用法,但對于符合條件的條目,我們都是返回整個 JSON 文件的。這類似于 SQL 里面的 SELECT *。有的時候,我們需要的,僅僅是部分?jǐn)?shù)據(jù),這個時候,find 的局部查詢的功能就派上用場了。先來看一個例子,返回 tags 為 drama 的電影的名字和首映日期。

          db.movie.find({'tags':'drama'},{'debut':1,'title':1}).pretty()

          數(shù)據(jù)庫將返回:

          {
           "_id" : ObjectId("549cfb42f685c085f1dd47d4"),
           "title" : "Forrest Gump",
           "debut" : ISODate("1994-08-05T16:00:00Z")
          }
          {
           "_id" : ObjectId("549cff96f685c085f1dd47d6"),
           "title" : "Fight Club",
           "debut" : ISODate("1999-11-14T16:00:00Z")
          }
          {
           "_id" : ObjectId("549cff96f685c085f1dd47d7"),
           "title" : "Seven",
           "debut" : ISODate("1995-10-21T16:00:00Z")
          }

          這里 find 的第二個參數(shù)是用來控制輸出的,1 表示要返回,而 0 則表示不返回。默認(rèn)值是 0,但 _id 是例外,因此如果你不想輸出 _id,需要顯式地聲明:

          db.movie.find({'tags':'drama'},{'debut':1,'title':1,'_id':0}).pretty()

          8. 更新

          很多情況下你需要更新你的數(shù)據(jù)庫,比如有人對某部電影點了個贊,那么你需要更新相應(yīng)的數(shù)據(jù)庫。比如有人對《七宗罪》點了個贊,而它本來的贊的個數(shù)是 134370,那么你需要更新到 134371。可以這樣操作:
          db.movie.updateOne({title:'Seven'}, {$set:{likes:134371}})

          第一個大括號里表明要選取的對象,第二個表明要改動的數(shù)據(jù)。請注意上述的操作相當(dāng)不現(xiàn)實,因為你首先要知道之前的數(shù)字是多少,然后加一,但通常你不讀取數(shù)據(jù)庫的話,是不會知道這個數(shù)(134370)的。MongoDB 提供了一種簡便的方法,可以對現(xiàn)有條目進(jìn)行增量操作。假設(shè)又有人對《七宗罪》點了兩個贊,則可以:

          db.movie.updateOne({title:'Seven'}, {$inc:{likes:2}})

          如果你查詢的話,會發(fā)現(xiàn)點贊數(shù)變?yōu)?134373 了,這里用的是 $inc。除了增量更新,MongoDB 還提供了很多靈活的更新選項。

          注意如果有多部符合要求的電影。則默認(rèn)只會更新第一個。如果要多個同時更新,要用 updateMany,像下面這樣:

          db.movie.updateMany({}, {$inc:{likes:10}})

          所有電影的贊數(shù)都多了 10.

          注意,以上的更新操作會替換掉原來的值,所以如果你是想在原有的值的基礎(chǔ)上增加一個值的話,則應(yīng)該用 $push,比如,為《七宗罪》添加一個 popular 的 tags。

          db.movie.updateOne({'title':'Seven'}, {$push:{'tags':'popular'}})

          我們查詢一下 db.movie.find({'title':'Seven'},{'tags':1,'title':1},你會發(fā)現(xiàn)《七宗罪》現(xiàn)在有四個標(biāo)簽:

          "tags" : [
            "drama",
            "mystery",
            "thiller",
            "popular"
          ],

          9. 刪除

          刪除的句法和 find 很相似,比如,要刪除標(biāo)簽為 romance 的電影,則:

          db.movie.deleteOne({'tags':'romance'})

          考慮到我們數(shù)據(jù)庫條目異常稀少,就不建議你執(zhí)行這條命令了。同樣地,該命令只刪除滿足條件的第一條記錄。如果要刪除滿足條件的所有記錄,則使用 deleteMany

          10. 索引和排序

          為文檔中的一些 key 加上索引(index)可以加快搜索速度。這一點不難理解,假如沒有索引,我們要查找名字為 Seven 的電影,就必須在所有文檔里逐個搜索。而如果對名字這個 key 加上索引值,則電影名這個字符串和數(shù)字建立了映射,這樣在搜索的時候就會快很多。排序的時候也是如此,不贅述。MongoDB 里面為某個 key 加上索引的方式很簡單,比如我們要對導(dǎo)演這個 key 加索引,則可以:

          db.movie.ensureIndex({directed_by:1})

          這里的 1 是升序索引,如果要降序索引,用 -1。

          MongoDB 支持對輸出進(jìn)行排序,比如按名字排序:

          db.movie.find().sort({'title':1}).pretty()

          同樣地,1 是升序,-1 是降序。默認(rèn)是 1。

          db.movie.getIndexes()

          將返回所有索引,包括其名字。而

          db.movie.dropIndex('index_name')

          將刪除對應(yīng)的索引。

          11. 聚合

          MongoDB 支持類似于 SQL 里面的 GROUP BY 操作。比如當(dāng)有一張學(xué)生成績的明細(xì)表時,我們可以找出每個分?jǐn)?shù)段的學(xué)生各有多少。為了實現(xiàn)這個操作,我們需要稍加改動我們的數(shù)據(jù)庫。執(zhí)行以下三條命令:

          db.movie.updateOne({title:'Seven'},{$set:{grade:1}})
          db.movie.updateOne({title:'Forrest Gump'},{$set:{grade:1}})
          db.movie.updateOne({title:'Fight Club'},{$set:{grade:2}})

          這幾條是給每部電影加一個虛擬的分級,前兩部是歸類是一級,后一部是二級。

          這里你也可以看到 MongoDB 的強(qiáng)大之處:可以動態(tài)地后續(xù)添加各種新項目。

          我們先通過聚合來找出總共有幾種級別。

          db.movie.aggregate([{$group:{_id:'$grade'}}])

          輸出:

          "_id" : 2 }
          "_id" : 1 }

          注意這里的 2 和 1 是指級別,而不是每個級別的電影數(shù)。這個例子看得清楚些:

          db.movie.aggregate([{$group:{_id:'$directed_by'}}])

          這里按照導(dǎo)演名字進(jìn)行聚合。輸出:

          "_id" : "David Fincher" }
          "_id" : "Robert Zemeckis" }

          接著我們要找出,每個導(dǎo)演的電影數(shù)分別有多少:

          db.movie.aggregate([{$group:{_id:'$directed_by',num_movie:{$sum:1}}}])

          將會輸出:

          "_id" : "David Fincher""num_movie" : 2 }
          "_id" : "Robert Zemeckis""num_movie" : 1 }

          注意 $sum 后面的 1 表示只是把電影數(shù)加起來,但我們也可以統(tǒng)計別的數(shù)據(jù),比如兩位導(dǎo)演誰的贊比較多:

           db.movie.aggregate([{$group:{_id:'$directed_by',num_likes:{$sum:'$likes'}}}])

          輸出:

          "_id" : "David Fincher""num_likes" : 358753 }
          "_id" : "Robert Zemeckis""num_likes" : 864377 }

          注意這些數(shù)據(jù)都純屬虛構(gòu)??!

          除了 $sum,還有其它一些操作。比如:

          db.movie.aggregate([{$group:{_id:'$directed_by',num_movie:{$avg:'$likes'}}}])

          統(tǒng)計平均的贊。

          db.movie.aggregate([{$group:{_id:'$directed_by',num_movie:{$first:'$likes'}}}])

          返回每個導(dǎo)演的電影中的第一部的贊數(shù)。

          其它各種操作可以參考:http://docs.mongodb.org/manual/reference/operator/aggregation/group/ 。

          12. All or Nothing?

          MongoDB 支持單個文檔內(nèi)的原子化操作(atomic operation),這是說,可以將多條關(guān)于同一個文檔的指令放到一起,他們要么一起執(zhí)行,要么都不執(zhí)行。而不會執(zhí)行到一半。有些場合需要確保多條執(zhí)行一起順次執(zhí)行。比如一個場景:一個電商網(wǎng)站,用戶查詢某種商品的剩余數(shù)量,以及用戶購買該種商品,這兩個操作,必須放在一起執(zhí)行。不然的話,假定我們先執(zhí)行剩余數(shù)量的查詢,這是假定為 1,用戶接著購買,但假如這兩個操作之間還加入了其它操作,比如另一個用戶搶先購買了,那么原先購買用戶的購買的行為就會造成數(shù)據(jù)庫的錯誤,因為實際上這種商品已經(jīng)沒有存貨了。但因為查詢剩余數(shù)量和購買不是在一個“原子化操作”之內(nèi),因此會發(fā)生這樣的錯誤。

          MongoDB 提供了 findAndModify 的方法來確保 atomic operation。比如這樣的:

          db.movie.findAndModify(
             {
             query:{'title':'Forrest Gump'},
             update:{$inc:{likes:10}}
             }
                  )

          Query 是查找出匹配的文檔,和 find 是一樣的,而 update 則是更新 likes 這個項目。注意由于 MongoDB 只支持單個文檔的 atomic operation,因此如果 query 出多于一個文檔,則只會對第一個文檔進(jìn)行操作。

          13. 文本搜索

          除了前面介紹的各種深度查詢功能,MongoDB 還支持文本搜索。對文本搜索之前,我們需要先對要搜索的 key 建立一個 text 索引。假定我們要對標(biāo)題進(jìn)行文本搜索,我們可以先這樣:

          db.movie.ensureIndex({title:'text'})

          接著我們就可以對標(biāo)題進(jìn)行文本搜索了,比如,查找?guī)в?"Gump" 的標(biāo)題:

          db.movie.find({$text:{$search:"Gump"}}).pretty()

          注意 text 和 search 前面的$符號。

          這個例子里,文本搜索作用不是非常明顯。但假設(shè)我們要搜索的 key 是一個長長的文檔,這種 text search 的方便性就顯現(xiàn)出來了。

          14. 正則表達(dá)式

          MongoDB 還支持基于正則表達(dá)式的查詢。這里簡單舉幾個例子。比如,查找標(biāo)題以 b 結(jié)尾的電影信息:

          db.movie.find({title:{$regex:'.*b$'}}).pretty()

          也可以寫成:

          db.movie.find({title:/.*b$/}).pretty()

          查找含有 'Fight' 標(biāo)題的電影:

          db.movie.find({title:/Fight/}).pretty()

          注意以上匹配都是區(qū)分大小寫的,如果你要讓其不區(qū)分大小寫,則可以:

          db.movie.find({title:{$regex:'fight.*b',$options:'$i'}}).pretty()

          $i 是 insensitive 的意思。這樣的話,即使是小寫的 fight,也能搜到了。

          db.movie.find({title: /fight.*b/i}).pretty()

          當(dāng)然,這樣也是可以,這是 JS 正則寫法

          15. 后記

          至此,MongoDB 的最基本的內(nèi)容就介紹得差不多了。如果有什么遺漏的以后我會補(bǔ)上來。如果你一路看到底完全了這個入門教程,恭喜你,你一定是一個有毅力的人。

          把這個文檔過一遍,不會讓你變成一個 MongoDB 的專家。但如果它能或多或少減少你上手的時間,或者讓你意識到 “MongoDB其實沒那么復(fù)雜”,那么這個教程的目的也就達(dá)到啦。

          作者:StevenSLXie

          鏈接:https://github.com/StevenSLXie/Tutorials-for-Web-Developers

          轉(zhuǎn)載請包含此聲明


          推薦閱讀

          IT運維面試問題總結(jié)-數(shù)據(jù)庫、監(jiān)控、網(wǎng)絡(luò)管理(NoSQL、MongoDB、MySQL、Prometheus、Zabbix)

          一款軟件,幾乎可以操作~所有的~“數(shù)據(jù)庫”,太牛逼了!

          終于不用愁了,GitHub 上的這些面試題項目我給你找好了。

          瀏覽 39
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操逼逼综合网 | 欧美黄片在线免费观看 | 亚洲观看黄 色 网 | 请立即播放黑人大屌日白人小嫩逼的视频 | 一区二区三区四区免费播放 |