· 前言
Mongoose是MongoDB的一個對象模型工具,基於node-mongodb-native開發。
初學node.js,之前看了一些博客,決定還是自己從官方文檔入手學習Mongoose,所以本文內容一部分是官方文檔的翻譯內容。留作筆記之用,有所側重,不會大而全。而且隨着理解加深會不斷充實本文內容。
環境說明
本文實踐是在win10下的mongoDB+Node.js+webstorm的環境上進行的。
connect
數據庫連接大同小異,以下是官網示例
mongoose.connect('mongodb://user:pass@localhost:port/database'); // replica sets var uri = 'mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/mydatabase'; mongoose.connect(uri); // with options mongoose.connect(uri, options); // connecting to multiple mongos var uri = 'mongodb://hostA:27501,hostB:27501'; var opts = { mongos: true }; mongoose.connect(uri, opts); // optional callback that gets fired when initial connection completed var uri = 'mongodb://nonexistent.domain:27000'; mongoose.connect(uri, function(error) { // if error is truthy, the initial connection failed. })
以下代碼是本文連接數據庫的方法:
var mongoose = require('mongoose'); var Schema = mongoose.Schema; mongoose.connect('mongodb://localhost/test'); var db = mongoose.connection; db.on('error', console.error.bind(console, 'connection error:')); db.once('open', function() { console.log('connected'); });
Schema
在Mongoose里一切都是從Schema開始的,每一個Schema都會映射到MongoDB的一個collection上。Schema定義了collection里documents的模板(或者說是框架)。
如下代碼定義了一個博客的Schema:
var blogSchema = new Schema({ // Schema頭字母大寫,因為Schema是構造函數 title: String, author: String, body: String, comments: [{ body: String, date: Date }], // 對象數組 date: { type: Date, default: Date.now }, // 通過default設置默認值 hidden: Boolean, meta: { // 嵌套對象 votes: Number, favs: Number } });
如果想對已經定義好的blogSchema添加鍵,可以用如下方法:
blogSchema.add({reprints : Number});
Schema支持的鍵值類型有String,Number,Date,Buffer,Boolean,Array,Objectld,Mixed。Schema不僅定義document的模板,而且可以定義document的實例方法。
_id
在MongoDB中同一個collection里的文檔都必有且唯一的“id”鍵用於唯一標識document,鍵值可為任意類型默認是ObjectId對象。ObjectId的設計初衷是為了分布式,所以不像傳統方法默認增加主鍵。這是一種輕量型設計,不同的機器可以用全局唯一的方法生成。ObjectId存儲空間是12字節,前四個字節是標准紀元時間戳(單位為秒),隱含該document的創建時間(由於大致是按時間順序存儲,故使用id作為索引的效率會很高)。后三個字節是主機唯一標志符,通常是主機名的散列值。接着后兩個字節是進程標識,最后三個字節是自動增加的計數器,確保同一秒內同一主機同一進程的ObjectId是唯一的。以上的生成document的id過程都是客戶端完成的,用以減輕服務器的開銷。
index
我們在定義Schema的時候可以定義其索引,一般是多重索引。
以下代碼是添加索引:
blogSchema.index({blogTitle : 1, reprints : -1});
這樣就建立了以blogTitel為正序,reprints為逆序的多重索引。
model
為了使用定義好的Schema,我們需要把blogSchema轉換成我們可以使用的model(其實是把Schema編譯成model,所以對於Schema的一切定義都要在compile之前完成)。也就是說model才是我們可以進行操作的handle。
以下代碼是編譯model的方法:
var Blog = mongoose.model('Blog', blogSchema);
這樣我們就獲得了一個名為Blog的model了。生成model的同時MongoDB中對應的collection也被建立了,model的名字是Blog,而collection的名字被默認是model名字的復數也就是blogs(細心的小伙伴會發現不止變復數了,而且字母全部變小寫了,親測是這樣的)。
官網中有關model()函數的用法如下:
Connection#model(name, [schema], [collection]) Defines or retrieves a model. Parameters: name <String> the model name [schema] <Schema> a schema. necessary when defining a model [collection] <String> name of mongodb collection (optional) if not given it will be induced from model name Returns: <Model> The compiled model
以下代碼是通過model生成document,以及document保存的方法:
var blog01 = new Blog({ blogTitle : 'The total eclipse of hreat', body : '........', comments : [{body : "That's awesome", date : new Date()}], hidden : false, state : { favors : 999, marks : 999 } }); blog01.save(function(err){ if (err){ return console.error(err); } console.log('saved'); })
真正跑過以上代碼就會發現MongoDB的容錯性很好,以上代碼其實在生成document時漏了一個鍵reprints賦值,但還是可以保存,而且在查詢該條document時reprints這個字段是不會顯示的。另外如果在生成document時,我們把鍵值的名字寫錯了,MongoDB還是可以忽略被輸錯的鍵的,把正確鍵對應的值存起來,忽略錯誤鍵名。
而且在id上,除了document有id,comments對應的對象數組也會有唯一id,如下圖:
Schema和model的理解
不同於關系型數據庫,MongoDB作為文檔型數據庫,Scheme、model、collection、document是其中的四大元素。document是MongoDB里的基本存儲單位,collection是眾多同類document的集合。Schema定義了一類document的模板,讓這一類document在數據庫中有一個具體的構成、存儲模式。而Schema僅僅是定義了Document是什么樣子的,至於生成document和對document進行各種操作(增刪改查)則是通過相對應的model來進行的。
需要說明的是MongoDB中實際上只有collection和document,Schema和model不過是定義和生成前二者過程中的工具而已。
總結
本文忽略了有關methods的介紹和connection與model之間的切換,主要是自己沒完全搞清楚,搞清楚了會加上
以下代碼是全文代碼匯總:

var mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/test'); var db = mongoose.connection; db.on('error', console.error.bind(console, 'connection error:')); db.once('open', function() { console.log('connected'); }); var Schema = mongoose.Schema; var blogSchema = Schema ({ blogTitle : String, body : String, comments : [{body : String, date : Date}], hidden : Boolean, state : { favors : Number, marks : Number } }); blogSchema.add({reprints : Number}); blogSchema.index({blogTitel : 1, reprints : -1}); var Blog = mongoose.model('Blog', blogSchema); var blog01 = new Blog({ blogTitle : 'The total eclipse of hreat', body : '........', comments : [{body : "That's awesome", date : new Date()}], hidden : false, state : { favors : 999, marks : 999 }, reprints : 999 }); blog01.save(function(err){ if (err){ return console.error(err); } console.log('saved'); }); mongoose.connection.close();