MongoDB 極簡入門實踐

1. 爲什麼用 MongoDB?

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

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

1SELECT ID, name 
2FROM products 
3WHERE cate='shoes' 
4AND price<300 and 
5AND promotion=true;
6
7

SQL 具備了強大了的深度查詢能力,能滿足各式各樣的查詢要求。而如果要對數據進行添加和刪除,成本也是非常低的。這些是 SQL 的優勢之一, 但隨着互聯網的興起以及數據形式的多樣化,四平八穩的 SQL 表單在一些領域漸漸顯現出它的劣勢。讓我們通過一個例子來說明。考慮一個博客後臺系統,如果我們用關係型數據庫爲每篇博客(article)建一個表單的話,這個表單大概會包括以下這些列:

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

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

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

那麼,如果用 MongoDB 數據庫來實現,可以如何設計數據模型呢?很簡單,像下面這樣:

 1 _id: POST_ID
 2   title: TITLE_OF_POST, 
 3   description: POST_DESCRIPTION,
 4   author: POST_BY,
 5   tags: [TAG1, TAG2, TAG3],
 6   likes: TOTAL_LIKES, 
 7   comments: [ 
 8      {
 9         user:'COMMENT_BY',
10         message: TEXT,
11         dateCreated: DATE_TIME,
12      },
13      {
14         user:'COMMENT_BY',
15         message: TEXT,
16         dateCreated: DATE_TIME,
17      }
18   ]
19
20

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

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

當然,除了上述的優點,MongoDB 還有不少別的優勢,比如 MongoDB 的數據是用 JSON(JavaScript Object Notation)存儲的 (就是上面的這種 key-value 的形式),適用於而幾乎所有的 Web 應用,存儲的數據和應用的數據的格式是高度一致的,不需經過轉換。

2. 關於這篇文章

這個極簡教程,或者說筆記,並不是一個覆蓋 MongoDB 方方面面的教程。所謂極簡的意思,就是隻選取那些最重要、最常用的內容進行基於實例的介紹,從而讓讀者能夠在最短的時間內快速上手,並且能順利地進行後續的縱深的學習。

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

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

3. 安裝與環境

3.1 使用 MongoDB Atlas + Compass(推薦)

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

簡單步驟如下:

3.2 本地架設 server

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

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

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

Mac OS X 下的安裝和設置:

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

4. 創建集合和刪除集合

在上一節執行完步驟 6 後,你會看到命令行裏顯示:connecting to: test,這裏的 test 是默認的數據庫。這裏我們可以新建一個數據庫。在命令行裏打入:

1use tutorial
2
3

這樣就新建了一個叫做 tutorial 的數據庫。你可以執行

1show databases
2
3

來顯示當前的數據庫。不過這時候由於我們的新數據庫是空的,所以會顯示類似這樣的:

1admin  (empty)
2local  0.078GB
3
4

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

1db.createCollection('author')
2
3

順利的話會顯示:

1{ "ok" : 1 }
2
3

表示創建成功。

你可以再回頭執行:

1show databases
2
3

這時候我們的 tutorial 集合已經位列其中。你可以再執行

1show collections
2
3

可以看到創建的集合 author 也在其中。

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

1db.author.drop()
2
3

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

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

5. 插入

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

顯然我們需要先創建一個叫電影的集合:

1db.createCollection('movie')
2
3

然後,我們就可以插入數據了:

 1db.movie.insert(
 2 {
 3   title: 'Forrest Gump', 
 4   directed_by: 'Robert Zemeckis',
 5   stars: ['Tom Hanks', 'Robin Wright', 'Gary Sinise'],
 6   tags: ['drama', 'romance'],
 7   debut: new Date("1994-07-06T00:00:00"),
 8   likes: 864367,
 9   dislikes: 30127,
10   comments: [ 
11      {
12         user:'user1',
13         message: 'My first comment',
14         dateCreated: new Date("2020-10-15T00:00:00"),
15         like: 0 
16      },
17      {
18         user:'user2',
19         message: 'My first comment too!',
20         dateCreated: new Date("2019-04-15T00:00:00"),
21         like: 0 
22      }
23   ]
24}
25)
26
27

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

把上面的例子複製進命令行應該可以順利運行,但我強烈建議你手動打一下,或者輸入一部你自己喜歡的電影。insert 操作有幾點需要注意:

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

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

1db.movie.find().pretty()
2
3

這裏 find() 裏面是空的,說明我們不做限制和篩選,類似於 SQL 沒有 WHERE 語句一樣。而 pretty() 輸出的是經格式美化後的數據,你可以自己試試沒有 pretty() 會怎麼樣。

仔細觀察 find() 的結果,你會發現多了一個叫 '_id' 的東西,這是數據庫自動創建的一個 ID 號,在同一個數據庫裏,每個文檔的 ID 號都是不同的。

我們也可以同時輸入多個數據:

 1db.movie.insert([
 2 {
 3   title: 'Fight Club', 
 4   directed_by: 'David Fincher',
 5   stars: ['Brad Pitt', 'Edward Norton', 'Helena Bonham Carter'],
 6   tags: 'drama',
 7   debut: new Date("1999-10-15T00:00:00"),
 8   likes: 224360,
 9   dislikes: 40127,
10   comments: [ 
11      {
12         user:'user3',
13         message: 'My first comment',
14         dateCreated: new Date("2020-10-15T01:00:00"),
15         like: 0 
16      },
17      {
18         user:'user2',
19         message: 'My first comment too!',
20         dateCreated: new Date("2020-11-15T01:00:00"),
21         like: 14 
22      },
23      {
24         user:'user7',
25         message: 'Good Movie!',
26         dateCreated: new Date("2020-10-15T08:00:00"),
27         like: 2
28      }
29   ]
30},
31{
32   title: 'Seven', 
33   directed_by: 'David Fincher',
34   stars: ['Morgan Freeman', 'Brad Pitt',  'Kevin Spacey'],
35   tags: ['drama','mystery','thiller'],
36   debut: new Date("1995-10-22T01:00:00"),
37   likes: 134370,
38   dislikes: 1037,
39   comments: [ 
40      {
41         user:'user3',
42         message: 'Love Kevin Spacey',
43         dateCreated: new Date("2020-12-15T01:00:00"),
44         like: 0 
45      },
46      {
47         user:'user2',
48         message: 'Good works!',
49         dateCreated: new Date("2020-10-15T11:22:33"),
50         like: 14 
51      },
52      {
53         user:'user7',
54         message: 'Good Movie!',
55         dateCreated: new Date("2020-08-15T01:00:00"),
56         like: 2
57      }
58   ]
59}
60])
61
62

順利的話會顯示:

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

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

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

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

6. 查詢

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

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

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

也可以設置多個條件。比如找出大衛芬奇導演的, 摩根弗里曼主演的電影:

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

這裏兩個條件之間,是 AND 的關係,只有同時滿足兩個條件的電影纔會被輸出。同理,可以設置多個的條件,不贅述。

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

1db.movie.find(
2{
3  $or: 
4     [  {'stars':'Robin Wright'}, 
5        {'stars':'Morgan Freeman'}
6     ]
7}).pretty()
8
9

注意這裏面稍顯複雜的各種括號。

還可以設置一個範圍的搜索,比如找出 50 萬人以上讚的電影:

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

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

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

類似地,少於二十萬人讚的電影:

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

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

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

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

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

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

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

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

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

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

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

7. 局部查詢

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

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

數據庫將返回:

 1{
 2 "_id" : ObjectId("549cfb42f685c085f1dd47d4"),
 3 "title" : "Forrest Gump",
 4 "debut" : ISODate("1994-08-05T16:00:00Z")
 5}
 6{
 7 "_id" : ObjectId("549cff96f685c085f1dd47d6"),
 8 "title" : "Fight Club",
 9 "debut" : ISODate("1999-11-14T16:00:00Z")
10}
11{
12 "_id" : ObjectId("549cff96f685c085f1dd47d7"),
13 "title" : "Seven",
14 "debut" : ISODate("1995-10-21T16:00:00Z")
15}
16
17

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

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

8. 更新

很多情況下你需要更新你的數據庫,比如有人對某部電影點了個贊,那麼你需要更新相應的數據庫。比如有人對《七宗罪》點了個贊,而它本來的讚的個數是 134370,那麼你需要更新到 134371。可以這樣操作:

1db.movie.updateOne({title:'Seven'}, {$set:{likes:134371}})
2
3

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

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

如果你查詢的話,會發現點贊數變爲 134373 了,這裏用的是 $inc。除了增量更新,MongoDB 還提供了很多靈活的更新選項。

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

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

所有電影的贊數都多了 10.

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

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

我們查詢一下 db.movie.find({'title':'Seven'},{'tags':1,'title':1},你會發現《七宗罪》現在有四個標籤:

1"tags" : [
2  "drama",
3  "mystery",
4  "thiller",
5  "popular"
6],
7
8

9. 刪除

刪除的句法和 find 很相似,比如,要刪除標籤爲 romance 的電影,則:

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

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

10. 索引和排序

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

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

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

MongoDB 支持對輸出進行排序,比如按名字排序:

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

同樣地,1 是升序,-1 是降序。默認是 1。

1db.movie.getIndexes()
2
3

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

1db.movie.dropIndex('index_name')
2
3

將刪除對應的索引。

11. 聚合

MongoDB 支持類似於 SQL 裏面的 GROUP BY 操作。比如當有一張學生成績的明細表時,我們可以找出每個分數段的學生各有多少。爲了實現這個操作,我們需要稍加改動我們的數據庫。執行以下三條命令:

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

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

這裏你也可以看到 MongoDB 的強大之處:可以動態地後續添加各種新項目。

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

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

輸出:

1{ "_id" : 2 }
2{ "_id" : 1 }
3
4

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

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

這裏按照導演名字進行聚合。輸出:

1{ "_id" : "David Fincher" }
2{ "_id" : "Robert Zemeckis" }
3
4

接着我們要找出,每個導演的電影數分別有多少:

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

將會輸出:

1{ "_id" : "David Fincher", "num_movie" : 2 }
2{ "_id" : "Robert Zemeckis", "num_movie" : 1 }
3
4

注意 $sum 後面的 1 表示只是把電影數加起來,但我們也可以統計別的數據,比如兩位導演誰的贊比較多:

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

輸出:

1{ "_id" : "David Fincher", "num_likes" : 358753 }
2{ "_id" : "Robert Zemeckis", "num_likes" : 864377 }
3
4

注意這些數據都純屬虛構啊!

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

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

統計平均的贊。

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

返回每個導演的電影中的第一部的贊數。

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

12. All or Nothing?

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

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

1db.movie.findAndModify(
2   {
3   query:{'title':'Forrest Gump'},
4   update:{$inc:{likes:10}}
5   }
6        )
7
8
9

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

13. 文本搜索

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

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

接着我們就可以對標題進行文本搜索了,比如,查找帶有 "Gump" 的標題:

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

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

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

14. 正則表達式

MongoDB 還支持基於正則表達式的查詢。這裏簡單舉幾個例子。比如,查找標題以 b 結尾的電影信息:

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

也可以寫成:

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

查找含有'Fight' 標題的電影:

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

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

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

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

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

當然,這樣也是可以,這是 JS 正則寫法

15. 後記

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

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

作者:StevenSLXie

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

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s?__biz=MzA5MzYyNzQ0MQ==&amp;mid=2247499494&amp;idx=2&amp;sn=8191afed5b3afc38ae55d19a5256f9de&amp;chksm=90584bb8a72fc2aee1006f0a88e36ade6474c001de7ce6da8d33e35d3d3899bed60ba1bd108f&amp;scene=132#wechat_redirect