BACK
Featured image of post 使用 Node.js 串接 MongoDB (含CRUD)

使用 Node.js 串接 MongoDB (含CRUD)

資料庫的連結對於網頁是不可或缺的,無論是 MongoDB 或是 Django,這種 NoSQL 的資料庫構建套件都十分的受程式設計師的歡迎,由於其不用再去學 SQL 格外的構築語法,NoSQL 就成為了廣為人知的開源資料庫,最近專案正好使用到 MongoDB,本篇來介紹一下 MongoDB、MongoDB 的安裝方式,以及使用 Node.js 串接 MongoDB 的 CRUD。

參考網站
參考網站
參考網站
參考網站
參考網站

資料庫的連結對於網頁是不可或缺的,無論是 MongoDB 或是 Django,這種 NoSQL 的資料庫構建套件都十分的受程式設計師的歡迎,由於其不用再去學 SQL 格外的構築語法,NoSQL 就成為了廣為人知的開源資料庫,最近專案正好使用到 MongoDB,本篇來介紹一下 MongoDB、MongoDB 的安裝方式,以及使用 Node.js 串接 MongoDB 的 CRUD。


MongoDB 資料庫簡介

MongoDB

MongoDB 是什麼?

MongoDB 是一種文件導向資料庫管理系統,由 C++ 撰寫而成,是一個以分散式檔案儲存為基礎的資料庫,旨在 Web 應用提供可擴充的高性能資料儲存解決方案。

  1. 它是 10gen 開發的 NoSQL (Not only SQL - 不只有 SQL)。
  2. 不是關聯式資料庫,沒有 Schema。
  3. 它是用來處理巨量資料的資料庫,這個資料庫是以文件導向儲存(Document Oriented Storage)的資料庫,以 key:value 表示,儲存格式與 JSON 完全一樣。
  4. 簡潔的文件模型。
  5. 容易水平擴展。
  6. 三層式的結構:
  • 資料庫(Database)
  • 集合(Collection)
  • 文件(Document)

MongoDB 的層級架構

MongoDB 世界的層級觀念,分別由大而小:

Database (資料庫)資料庫,儲存所有「表」跟資料的地方,在一個 MongoDB 伺服器中通常會有一至多個 Database,通常將不同的應用放在不同 database 中。
Collection (集合): 就是資料表,概念好比關聯式資料庫的 Table。通常一個 databse 中會有數個 collection。
Document (文件): 就是一筆資料,概念就如同關聯式資料庫的 Row。通常一個 collection 中會有數筆 document。也因此我們稱 MongoDB 是 document database。

MongoDB 資料 v.s. 關聯式資料庫

關聯式資料庫(RDBMS)MongoDB
DatabaseDatabase
TableCollection
Tuple/RowDocument
ColumnField
Table JoinEmbedded Documents
Primary KeyPrimary Key (如果沒有設定,mongodb會自動給予 預設主鍵值 _id 欄位)

BSON?

BSON 就是 JSON 格式的 key-value 組合,採用 JSON 的二進位表示。

MongoDB 在儲存資料時,都必須採用 BSON 格式做處理。

使用 BSON 的優點包含:

  • 在空間儲存上較有效率
  • 有更多 type(資料格式) 可以使用:如 ObjectId、Regular Expression、Timestamp 等,都是 BSON 支援的格式

我們以網站結構範例來示範:

  • 會員資料
1
2
3
4
5
6
7
8
9
{
  "email": "[email protected]",
  "password": "54875487"
},
{
  "email": "[email protected]",
  "password": "54875487"
},
...

因為 MongoDB 的 schemeless 特性,當我們突然想為其中一個 user 紀錄手機,只需要在那個 user 的 document 中加入「手機」這個新欄位就行,其他 user 完全不受影響。

  • 會員資料
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "email": "[email protected]",
  "password": "54875487"
},
{
  "email": "[email protected]",
  "password": "54875487",
  "phone": "0912345678"
},
...

實際上 BSON 支援的 type 有很多,這邊我們再舉一個包含多種 type 的 document 當作範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "_id": ObjectId("5099803df3f4948bd2f98391"), // _id 屬性是 ObjectId,常作為主鍵
  "name": { "first": "Alan", "last": "Turing" }, // name 屬性是 object
  "email": "[email protected]",
  "password": "54875487",
  "phone": "0912345678",
  "birth": new Date('Jun 23, 1912'), // bitrh 屬性是日期
  "death": new Date('Jun 07, 1954'),
  "contribs": [ "Turing machine", "Turing test", "Turingery" ],
  "views": NumberLong(1250000)
}

在 Windows 上安裝 MongoDB

在安裝前,我們先來確認 Windows 版本。

在終端機輸入,並執行:

1
2
3
4
wmic os get osarchitecture

> OSArchitecture
> 64-bit # 顯示出所用的 OS 是哪一種結構。

接著,我們去 MongoDB Downlad Center 下載所需套件:

下載後,可以參考 Install on Windows 我們就依此文件,做以下的操作:

安裝流程

  1. Step 1.

  1. Step 2.

  1. Step 3. 可以選 Custom 安裝,這裡就可以設定安裝的路徑。

  1. Step 4. 系統預設是安裝在 C:\Program Files\MongoDB\Server\6.0\ 那我們這裡就依照官方的,不改。

  1. Step 5.

  1. Step6. 完成

Bonus(一): 下載 mongosh.exe

前往安裝目錄下 /bin 目錄中,會發現沒有 mongo.exe 檔案,原因在於:MongoDB 6.0 以後做出了重大改變,已經不再預設為你安裝 shell 工具,因此需要安裝一個額外的 shell:Install mongosh – MongoDB Shell,這個工具被稱為 mongosh

前往頁面下載 mongosh.exe,下載後將解壓縮出來的 bin 資料夾內的檔案,複製到安裝目錄下 /bin 目錄中。

直接點擊 mongosh.exe 即可進入 MongoDB shell 界面。

Bonus(二): “mongo” 不是內部或外部命令

要執行 MongoDB Shell,還需要回到 /bin 目錄底下,無法在任意地方執行 MongoDB Shell,原因:環境變數未設定。

設定步驟:

  1. “開始"選單點選右鍵 -> 系統 -> 進階系統設定。

  2. 點選"進階” -> 環境變數。

  1. 系統變數的 Path,點擊"編輯"。

  2. C:\Program Files\MongoDB\Server\6.0\bin 加入原本字串後方!

(新版的 Windows,C:\... 前面可以不用加分號 ;C:\...)

  1. 確定後即可在任意地方,啟動你的 MongoDB、MongoDB Shell。

Bonus(三): 移除 MongoDB 服務

有安裝服務,就也有移除服務,如果你決定要移除 MongoDB 服務,可以在終端機執行:

1
2
3
"C:\Program Files\MongoDB\Server\6.0\bin\mongod.exe" --remove
# or
# mongod --remove

執行啟動 MongoDB

MongoDB 預設資料庫存放位置是 ${安裝目錄}\data\db,所以我們可以建立這樣的資料庫路徑:

C:\ 以 Command pormpt 執行:

1
mkdir \MongoDB\data\mydb

接著執行:

1
cd "C:\Program Files\MongoDB\Server\6.0\bin"

目前,我們位在 C:\Program Files\MongoDB\Server\6.0\bin >

輸入:

1
mongod --dbpath c:\MongoDB\data\db

啟動同時,指定資料庫存放位置!

接著,出現像這樣的畫面,表示 MongoDB 已經正常啟動了!

你就可以開始使用了!

可以參考一些文件 Getting Started 來做測試。

Note: 關於資料庫存放位置,其實可以自己設定好一個資料夾位置,指定過去就好囉!不限於一定得在 \data\db 之下!


使用 MongoDB Shell

連線資料庫

資料庫啟動以後,我們開啟另一個終端機執行:

1
2
mongosh
# .exe 可以不用

啟動 MongoDB Shell 環境,當我們看到如圖畫面,代表連線 MongoDB 成功:

查看與使用資料庫

我們可以做一些簡單的查詢,比方 show dbs 可以看到底下有哪些資料庫。

要使用資料庫 TestDB,可以用 use TestDB

如圖:

關閉資料庫

  • 離開 MongoDB Shell,使用 exit
  • 關閉 MongoDB 服務、關閉資料庫、中斷連線,在 admin 資料庫下,使用 db.shutdownServer()

觀看指令資料庫裡面的集合

1
show collections

新增一筆資料 inserOne

1
2
3
db.rooms.insertOne(
  { name: "單人房", price: 1000, rating: 4.5 }
)

新增多筆資料 insertMany

1
2
3
4
5
6
db.rooms.insertMany(
  [
    { name: "豪華單人房", price: 1500, rating: 4.3 },
    { name: "雙人房", price: 2000, rating: 4.8 },
  ]
)

尋找集合裡面的資料

1
db.collections.find()
  • 一般搜尋:
    • db.<集合名稱>.find()
    • 尋找對應屬性:db.collections.find({屬性名稱:屬性值})
    • 模糊搜尋:db.rooms.find({"name":/雙/})
    • 數值區間:db.collections.find({屬性名稱:{$lte:400}})
    • 複合條件:db.collections.find({屬性名稱:{$lte:400},rating:{$gte:4.8}})
  • 常用語法:
    • project 保護欄位:db.rooms.find({"name":/雙/},{"_id":0})
    • 搜尋陣列裡面的值:db.rooms.find({"payment":{$in:["信用卡"]}}
運算子說明
$eq等於
$gt大於
$lt小於
$gte大於等於
$lte小於等於
$in存在某個值
$nin不存在某個值
or
and

舉個例子:

1
2
3
4
5
6
7
8
db.rooms.find( 
  { $and:
    [
      { price: { $lte:1500 } },
      { rating: { $gte:4.5 } }
    ] 
  } 
)

修改(updateOne)

updateOne

replaceOne() 只能替換整個文件;updateOne() 允許更新欄位。

1
2
3
4
5
6
7
8
db.rooms.updateOne(
  {
    "_id": ObjectId("621edf99a20aa7506a116f9a")
  },
  {
    $set: { name: "修改雙人房" }
  }
)

修改多個值

修改多個值 updateMany(filter 篩選 > $set 更換設定)

1
2
3
4
db.rooms.updateMany(
  { rating: { $gt:4.5 } },
  { $set: { price:300 } }
)

替換整個文檔:replaceOnereplaceMany

1
2
3
4
5
6
7
db.collection.replaceOne(filter, replacement, options)

-- 舉個例子:
db.rooms.replaceOne(
  { "_id": ObjectId("621edf99a20aa7506a116f9a") },
  { name: "yes~" }
)

刪除多個文件:deleteMany(filter)

1
2
3
db.rooms.deleteMany(
  { rating: { $gte:4.3 } }
)

資料集結購

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[
  {
    "rating": 4.5,
    "price": 1000,
    "name": "標準單人房",
    "payment": ["信用卡","ATM"]
  },
  {
    "rating": 4.3,
    "price": 1500,
    "name": "豪華單人房",
    "payment": ["信用卡","ATM"]
  },
  {
    "rating": 4.8,
    "price": 2000,
    "name": "標準雙人房",
    "payment": ["信用卡","ATM"]
  },
  {
    "rating": 4.7,
    "price": 2500,
    "name": "豪華雙人房",
    "payment": ["ATM"]
  },
  {
    "rating": 4.0,
    "price": 3000,
    "name": "標準四人房",
    "payment": ["現金"]
  },
  {
    "rating": 3.5,
    "price": 10000,
    "name": "總統套房",
    "payment": ["現金"]
  }
]

查詢指令使用,好用的 help


配置 MongoDB 服務

如果,我們想要將操作 MongoDB 的記錄,寫進 log 裡。

我們先建立一個放置 log 的資料夾,為了有規律的放置檔案:

  • C:\MongoDB\data\db 放置 database
  • C:\MongoDB\data\log 放置 log

所以,建立一個資料夾 log

1
2
# 於 C:\MongoDB\data 下
mkdir log

接著,我們要建立一個 config 檔案,它是 MongoDB 的配置檔,內容可以配置 db 路徑(storage.dbPath)及 log 寫入檔案(systemLog.path)。

C:\MongoDB\data\log\mongod.cfg
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
storage:
  dbPath: C:\MongoDB\data
  journal:
    enabled: true
 
systemLog:
  destination: file
  logAppend: true
  path: C:\MongoDB\data\log\mongod.log
 
net:
  port: 27017
  bindIp: 127.0.0.1

接著,我們以系統管理員身份啟動終端機

1
2
# 安裝設定(cfg 檔位置必須為絕對路徑,否則會報錯)
mongod --config "C:\MongoDB\data\log\mongod.cfg" --install

接著,我們就可以直接在任意位置,以簡單的方式,啟用服務,而不用每次啟動,都要指向資料庫位置。

不再用 mongod –dbpath C:\MongoDB\data\db 這一長串東西。

啟用服務:

1
net start MongoDB

停用服務:

1
net stop MongoDB

如圖:

每執行服務,都會寫一次 log 檔,在我們當初配置的資料夾。

以上,我們已經完成了 MongoDB 的安裝與執行,再來說明使用 Node.js 串接 MongoDB 做 CRUD。


Node.js 串接 MongoDB 做 CRUD

這邊先著重 Node.js 概括的學習,閒有餘力,再深入 MongoDB。

關於 MongoDB 比較基礎且重要的,可以先參考:

MongoDB CRUD Operations

它裡面教你如何在 MongoDB 裡新增、讀取、更新、刪除的基本資料操作。

這邊我直接參考 access-mongodb-in-nodejs 完成此篇這一系列的 Node.js 學習。

那我們開始吧!

NPM 安裝 MongoDB driver

我們需要安裝 mongodb-driver,在終端機輸入:

1
2
3
npm install mongodb -g
cd myapp
npm install mongodb --save

我們打開 package.json 看,安裝了 mongodb: "5.0.0" (注意,這裡安裝的是 driver,不是 MongoDB 喔!)

啟動 MongoDB Server

接著,我們要啟動我們的 MongoDB Server,可在終端機輸入:

1
2
3
# 也可以直接在 myapp 裡建一個測試的數據資料庫存放位置
mkdir testdb
mongod --dbpath c:\myapp\testdb

或是,如果已經設定好 config 的 MongoDB service,那就直接使用:

1
net start mongodb

註:這邊可能要用系統管理員身份執行終端機才可以正確執行!

Node.js 連接 MongoDB

mockserver.js
1
2
3
4
5
6
7
8
9
let MongoClient = require('mongodb').MongoClient;
 
// Connect to the db
MongoClient.connect("mongodb://localhost:27017/mymondb", function(err, db) {
  if(err) throw err;
  // Write databse Insert/Update/Query code here..
  console.log('mongodb is running!');
  db.close(); // 關閉連線
});

這個例子裡,我們載入 MongoDB module,並且使用 MongoClient 物件。

接著,使用 MongoClient.connect() 方法,以取得 MongoDB 資料庫的引用。

其中,URL 的部份,"mongodb://localhost:27017/mymondb",指向你之前指定的 MongoDB 資料夾位置 C:\myapp\testdb

connect() 方法,會回應一個 database 參考 ,如果所描述的 database (這裡的例子叫做 mymondb) 存在,就連線;無就自動新增。

我們來看看,以上例子,如果有成功連線時的執行結果:

當我們建立了 Node.js 與 MongoDB 連線後,可以使用 connect() 裡的回呼函式其 DB 參數,開始做一些新增Insert(Create)、更新Update、查詢Query(Retrieve/Read)、刪除Delete 資料的動作。

新增(Insert/Create)資料

現在,我們來為我們的資料庫新增一些資料。

moncreate.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
let MongoClient = require('mongodb').MongoClient;
 
MongoClient.connect("mongodb://localhost:27017/mymondb", function(err, db) {
 
  if(err) throw err;
  //Write databse Insert/Update/Query code here..

  db.collection('Persons',function(err, collection) {
    collection.insert({ id:1, firstName:'Steve', lastName:'Jobs' });
    collection.insert({ id:2, firstName:'Bill', lastName:'Gates' });
    collection.insert({ id:3, firstName:'James', lastName:'Bond' });

    collection.count(function(err, count) {
      if(err) throw err;
      console.log('Total Rows:' + count);
    });
  });
  db.close(); // 關閉連線
});

在這個例子中,我們用 db.collection 方法去新增並且獲取 collections 的一些資訊,如總筆數。

別忘了,在介紹 MongoDB 與關聯式資料庫的關係時,我們知道 collection 其實就是 table

而這個例子裡,我們在 mymondb 資料庫 建立了一個 Persons - collection(資料表),並且,為這 Persons 資料表新增了 3 筆資料,我們在這裡叫 documents (列)

結果如圖:

我們也可以使用 Mongo Shell,查詢:

更新(Update)資料

做完了新增,如果我們想要更新其中 id == 1 的資料。

monupdate.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
let MongoClient = require('mongodb').MongoClient;
 
MongoClient.connect("mongodb://localhost:27017/mymondb", function(err, db) {
  db.collection('Persons',function(err, collection) {
    // collection.update
    // 第一個參數是要更新的條件
    // 第二個參數 $set:更新的欄位及內容
    // 第三個參數 writeConcern
    // 第四個參數執行 update 後的 callback 函式
    collection.update(
      { id: 1 },
      { $set: { firstName: 'James', lastName: 'Gosling'} },
      { w: 1 },
      function(err, result) {
        if(err) throw err;
        console.log('Document Updated Successfully');
      }
    );
  });
  db.close(); // 關閉連線
});

我們在終端機執行 node,並且在 Mongo Shell 可以看到更新前與更新後的資料,如圖:

關於第三個參數 - writeConcern

這個網站有詳細說明,可以去參考看看,我們這裡使用,常用的 {w:1} 即可,不用也沒差!

刪除(Delete)資料

現在,我們想要刪除 id == 2 的 Document(Row)。

mondelete.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
let MongoClient = require('mongodb').MongoClient;
 
MongoClient.connect("mongodb://localhost:27017/mymondb",function(err, db) {
  db.collection('Persons', function(err, collection) {
    collection.remove(
      { id: 2 },
      { w: 1 },
      function(err, result) {
        if(err) throw err;
        console.log('Document Removed Successfully!');
      }
    );
  });
  db.close(); // 關閉連線
});

我們在終端機執行 node,並且在 Mongo Shell 可以看到刪除前與刪除後的資料,如圖:

查詢(Query)資料

維持 Persons 新增後的狀態!即原本的3筆!現在,我們想要找 firstName == “Bill”

monquery.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
let MongoClient = require('mongodb').MongoClient;
 
MongoClient.connect("mongodb://localhost:27017/mymondb", function(err, db) {
  db.collection("Persons", function(err, collection) {
    collection.find({ firstName: "Bill" }).toArray(function(err, items) {
      if(err) throw err;
      console.log(items);
      console.log("We found " + items.length + " results!");
    });
  });
  db.close(); // 關閉連線
});

我們在終端機執行 node,可以看到被擷取出來的結果,如圖:

!!重要!!
關於更多 Collection 的操作,可以參考:Collection Methods,特別在使用查詢 find,有不同於以往 SQL 的使用語法。


comments powered by Disqus