[Note] Mongodb – tiny and elegant database

Image Credit  :  1 , 2

最近在開發一個分享書籍資訊的服務,因為想要試著單靠 JavaScript 去征服這個世界,所以我就選定了以下的開發環境及工具:

  • Node.js ( server side javascript )
  • Express.js ( web framework based on Node.js )
  • MongoDB

因為書藉的資訊在這個服務中沒有太大的關聯性,同時我也懶得搞一個複雜的資料庫出來,所以在大量的 Survey 後,我發現 MongoDB 很適合當這個服務的資料庫後端 。

使用原因

所謂事出必有因,我特別列出幾個它吸引我的原因如下:

  1. JSON-style documents
    Document 在 MongoDB 裡的名詞定義就是一組一組的資料集合,而它有一個很棒的特色,就是所有的 Document 都是以 JSON 的風格存儲 ,所以在存儲資料的時候可以很方便的統一格式。
  2. Dynamic Schema
    我們在操作資料庫的時候可以不用操心 Schema 的問題,因為 Collection (等同於 RDBMS 中的 Table)的 Schema 是在你存入 Document 的時候依其型態決定的,所以還可以做到同一個 Collection 的 Document 有不同的資料型態(雖然這通常不會是我們允許的情況,但是做的到)。
  3. Easy Querying
    在操作 MongoDB 的時候,我們可以不用和一堆複雜的 SQL 語法打交道(如: CREATE TABLE / ALTER TABLE …),而是透過多個 Query Object 來存取資料,所以這對於熟悉 JavaScript 的開發者來說,真的是很直覺的操作方式。

善用 Modules

而在開發服務的時候,為了找到好用的 Node Modules 來操作 MongoDB,我就到處在 npm 尋找可行的 MongoDB modules,但是幾本上都不方便使用,光是原生的 MongoDB-native 也因為要寫一堆 callback function 而被我打槍…

就在萬念具灰的時候,我發現了一個名為「Mongolian」的 Module。

比較 Modules 差異

不用一段 Source Code 很難明確的點出 MongoDB-native 和 Mongolian 的落差,所以先來看一段 VCR(註解在程式碼裡):

https://gist.github.com/2957876.js

如果你還看不出 MongoDB-native 的 callback 大軍的話,那再看另一段從官方範例中完整取出的 VCR:

https://gist.github.com/2957935.js

這真的是太噁心了,我實在是沒有辦法使用這一串 callback 海來操作資料庫,所以我最後選用了還在這個還在開發階段中的 Mongolian,不單單只是因為操作簡單,還因為它完整的提供了和 MongoDB shell 一樣的操作流程,這對開發者來說真的是好事呀,這就是所謂的一魚兩吃!

Mongolian DeadBeef is an awesome Mongo DB node.js driver that attempts to closely approximate the mongodb shell.

而使用方式就不詳述了,因為這個去看 Document 還有 Example 甚至是多玩幾次 MongoDB shell 就會了,就請自己多方嘗試吧。

BSON ObjectId

我還要特別記錄一下這個叫做 ObjectId 的東西,如果你仔細去印出存在於 Collection 中的 Document 的話,你會發現每一組 Document 都會有一個 _id 的欄位存放著 ObjectId,原先我單單以為這只不過是一個類似 unique id 的機制,可以讓你明確的區分出各個 Document ,結果我錯了,因為他還有更深層的含意在背後。

BSON ObjectId 是一個大小為 12 bytes 的資料型態,從下表可以看出他每個資料區段所代表的意義。經過我的研究後發現,後三個資料區段主要是在提供 ObjectId 的獨特性以避免 Collision 的情況發生,所以其實並沒有太大的實質意義,真正特別的是 time 那個資料區段。

TimeStamp. This is a unix style timestamp. It is a signed int representing the number of seconds before or after January 1st 1970 (UTC).

WTF,他們聰明到把 Timestamp 藏在一個原本只是為了 Uniqueness (唯一性) 而存在的欄位,不僅因為 Timestamp 本身就具有唯一性,還具有實質上的意義呀!如果我們的 Document 存的是使用者的個人資訊,那你的 ObjectId 本身就代表著這個使用者創立帳號的時間,你就不需要再另外設計一個多餘的欄位來做這件事情,你只要這樣做就可以得到這個資訊:

o.getTimestamp() // ISODate("2012-06-20T03:40:58Z")

是不是很驚人?對我來說,真正驚人的是它背後的設計理念,這就像是 reCaptcha 為 Captcha 附予附加意義一樣,讓原本的惱人的 Captcha 驗証行為變成利用眾人的智慧去辨識無法辨別的古書,改變了原本被視為理所當然的事物,同時也附予其更深層的意義。

這才是所謂的「創新」,在你附予那些被視為理所當然的事物更深層意義之後。

以上就是這次的記錄,下次我們再來更深入了解 MongoDB 吧!