2012年9月8日 星期六

NoSQL Database - MongoDB & Node.js

這篇文章主要是介紹 MongoDB 這個資料庫,也會用 Node.js 與其相連,不過在這之前,先來解說一下一些名詞,首先就是 NoSQL,從 Wikipedia 看來就是不用 SQL 當做查詢的語言,換句話說,如果用 MongoDB 就不用學 SQL 了,呵。看來不錯,再來看看 MongoDB 有什麼特色,MongoDB 是一種文件導向的資料庫,什麼文件?長什麼樣子?舉一個例子來說
{
    name : "Michael"
    gender : "Male"
}
長得和 JSON 好像啊,嗯啊,可以直接把 JSON 丟到 MongoDB 裡,這個就是文件,還可以很複雜如下
 {
     "query": "Pizza",
     "locations": [
         1210054,
         1201167
     ]
 }
就是一個 JSON 所以用 Javascript 存取 MongoDB 非常直覺。OK 讓我們來安裝一下 MongoDB
安裝有幾種方式比如有 Homebrew 直接用
brew install mongodb
或者到這安裝執行檔,有幾個作業系統可以選如下
 安裝完之後在 Terminal 可以輸入以下指令,來確定安裝成功。
mongod --version
可以看到如下畫面
 這樣就是成功安裝了。好吧,我們開啟這個 MongoDB 服務,很簡單,直接輸入 mongod 這樣就可以了
mongod
不過,讀者有可能會看到以下的畫面,代表沒有開啟服務成功
 紅色框起來的部分,寫著
MongoDB starting : pid=4116 port=27017 dbpath=/data/db/ 64-bit host=chronoers-MacBook-Air.local
MongoDB 想要在 port 27017 開啟,而且把資料放在 /data/db/ 這個資料夾下,然後就是shutdown 了,很有可能就是 port 27017 被別人用了,或是 dbpath 這個目錄不存在,一開始沒有別的服務的話,dbpath 的這個目錄不存在的可能性很高,這篇文章的做法就是先在當下目錄下建立一個新的目錄名為 dbs,如下指令
mkdir dbs
然後再啟動 MongoDB ,這次要改變一些參數,如下
mongod --dbpath=dbs
這樣一來 mongod 就會用當前的目錄下的 dbs (剛剛我們建立的),來存放資料,執行成功後會看到如下畫面
最後寫 waiting for connections on port 27017 然後整個游標停在那,這樣就表示正常啟動了。
我們先用 Terminal 來新增一些資料到 dbs 裡面,在先前有提過 document 的觀念,基本上可以視為一個 JSON 物件。接者要來說另一個名詞叫 collection,很多筆 document 就組合成一個 collection ,所以我們要新增一筆 document 之前要先建立一個  document ,這是 MongoDB 的架構,OK。
怎麼新增呢?我們在安裝完成後,除了有 mongod 這個指令外,還有另一個叫做 mongo 要注意,只差一個 d,符號,mongo 就是要和 mongod 來溝通的指令,首先先來看一下版本
直接執行
mongo
會看到如下畫面
 游標停在 > 之後,代表可以直接輸入指令,控制 mongod,如下輸入
show dbs
代表把所有的 database 呈現在 Terminal 上,應該會看到如下


local (empty) 就是有一個資料庫名為 local 但是沒有資料在裡面。我們就來新增一個資料庫名為 mydb,如下輸入
use mydb
會看到
雖然沒有明確看到建立的動作,  因為 mydb 裡面如果沒有 document 或 collection 是沒有意義的,暫時這樣,先來看一下這個 mydb 一些基本內容
db.stats()
這樣會看到
還記得 collection 和 document 嗎?我們就來建立一下。輸入
db.users.insert({name : "Michael", gender : "Male"})
如果沒有發生錯誤,就會看到如下
users 這個就是 collection  而 {name : "Michael", gender : "Male"} 就是 document ,insert 就是寫入的動作,就這樣很直接的寫就可以新增資料進入 mydb 了,我們用
show collectons 就可以看到如下,有出現  users

users 真得有寫入 mydb 接下來看 users 這個 collection 裡面的內容,使用如下指令
db.users.find()
會看到如下
真得有一筆資料,接下來我們做個實驗
再輸入一次
db.users.insert({name : "Michael", gender : "Male"})
再用
db.users.find()
會發生什麼事?

兩筆我們認為一樣的資料寫入了,MongoDB 不會因為 name, gender 一樣的值就自行判斷不加入哦,對 MongoDB 而言就是兩筆資料,而兩筆的 _id 是不一樣的,那接下來把其中一個刪除吧。用下列指令
db.users.remove({"_id" : ObjectId("5048d6b704f6c8a66750e12b")})
因為 _id 才是可以辦識不一樣的key 所以要輸入 _id 才可以明確指出要 remove 那一筆 document 。接下來我們來更改一下內容,用 update,如下
db.users.update({gender : "Male"}, { $set :{ name : "James" }})
再用
db.users.find()
把結束呈現出來會看到下方結果

 name 改成了 James 了,我們來看一下 update 這個 function 有兩個參數,第一個參數是要尋找的條件,我們設定為 {gender : "Male"} 目前也只有一個 document 符合,接下來第二個參數是
{ $set : { name : "James"}}
 前面要加上 $set 會依照原本的值 {name : "Michael", gender : "Male"} 做為改變的依據,把 name 這個值改成 James,如果沒有加上 $set 比如說
db.users.update({gender : "Male"}, { name : "James" })
則會把原本的 {name : "Michael", gender : "Male"} 用 { name : "James" } 取代,也就是說  { gender : "Male "} 並不會被保留。
好我們介紹了 insert, find, update, remove 這幾個操作就是有名的 CRUD - (Create,Read,Update,Delete),接下來我們來看一下怎麼從 Node.js 來存取 MongoDB 的資料。
首先把上面的 MongoDB 停止,需要輸入  Ctrl + c。然後再另一個資料夾再開啟一個新的 Server。我們就建立一個名為  mongoDemo 的資料夾,然後在 mongoDemo 之下再建立 dbs 。然後開啟 MongoDB 如下輸入
mongod --dbpath dbs
我們必需要為 Node.js 準備一個 MongoDB 的 Driver,名為 mongojs 如下安裝
npm install -g mongojs
也許有些網友比較熟 mongodb 這個官方網站介紹的 module ,不過這篇文章開頭是用 mongo 這個 interactive shell 來介紹存取 MongoDB 的而 mongojs 的寫法和 mongo 比較像,所以就先採用這個,mongojs 的官方 GItHub 在。而對官方的 mongodb 比較有興趣的讀者可以看這篇解釋
接著準備一個名為 accessMongo.js 的檔案, 先輸入如下內容。

var express = require("express");
var app = express();
app.listen(8800);
var config = {
    "hostname":"localhost",
    "port":27017,
    "db":"mydb"
}
var dbURL = "mongodb://" + config.hostname + ":" + config.port + "/" + config.db;
var collections = ["users"];
var db = require("mongojs").connect(dbURL, collections);
 一開始筆者還是使用了 express,為了方便可以讓使用者看到結果。預計用
http://127.0.0.1:8800/create
http://127.0.0.1:8800/read
http://127.0.0.1:8800/update
http://127.0.0.1:8800/remove
這四個 GET 連結來來代表對 Database 執行 CRUD 四個動作。
接著我們會看到 config 這個 JSON Object 就是關於要存取 MongoDB Database 和  Collection 的設定。最後利用 mongojs 的 connect 和 MongoDB 連上線並設定要存取的 collection 是 users。接下來寫 read 的部分。


app.get("/create",function  (req, res) {
            db.users.save({name: "Michael", gender: "Male"}, function(err, saved) {
             if( err || !saved ) console.log("User not saved");
                 else {
                          res.send("User saved");
             }
                  res.end();
            });
});
在這裡我們可以看到 db.users.save() 幾乎和 mongo 終端機的寫法一樣,第一個參數就是 document 也就是 {name: "Michael", gender: "Male"},如果 saved 是正確的,代表寫入正確再來我們來寫 read,如下。

app.get("/read",function  (req, res) {
    db.users.find({}, function(err, users) {
      if( err || !users) console.log("No  users found");
      else users.forEach( function(user) {
        res.send(JSON.stringify(user)+"\n");
      } );
      res.end();
    });
});
用 db.users.find() 第一個參數是 {} 代表任一個 document 都符合,然後第二個參數是個 function,其中 users 就是從 users.find() 找到的所有的 document 就會存在這個 users array 裡面。然後用 users.forEach() 把每個 document 送給 Browser 呈現出來。如此一來就可以先用 Browser 測試,記得要先開啟 mongod 才能執行 node accessMongo.js。
在 Browser 輸入 http://127.0.0.1:8800/create
再來測試 read http://127.0.0.1:8800/read
恭喜大家表示成功了。
再來就是 update。新增程式碼如下。

app.get("/update",function  (req, res) {
    db.users.update({name: "Michael"}, {$set: {name: "James"}}, function(err, updated) {
      if( err || !updated ) console.log("User not updated");
      else {
          res.send("User updated");
          res.end();
      }
    });
});
和 mongo 的 interactive shell 非常像用 db.users.update 然後第一,二個參數就是 {name: "Michael"}, {$set: {name: "James"}} 和 Terminal 寫法一樣。沒有錯誤的話,
輸入 http://127.0.0.1:8800/update 就會在 Browser 看到如下
表示 update 成功,然後再輸入 http://127.0.0.1:8800/read
同一個 id 名字改成了 James。
最後我們要來測試一下 Delete ,新增如下程式碼

app.get("/remove",function  (req, res) {
    db.users.remove({gender: "Male"});
    res.send("removed ");
    res.end();
});
remove 這個 function 就是把尋找的條件丟入,就可以了,如果用 {} 表示要刪除全部的 documents。在Browser 輸入 http://127.0.0.1:8800/remove
 然後用 read 確定,輸入
空空如也,就是我們要的了。好吧,今天就到此了,咱們下次見。例子一樣放在 GitHub。謝謝各位看倌們。

沒有留言:

張貼留言