用過 MongoDB 的人應該都知道它是沒有關係型數據庫裏的 join 特性的,這意味着當咱們使用 MongoDB 讀取某個 document 及其關聯的 document 的字段的時候,變得尤其麻煩。數據庫
基於此,Mongoose 封裝了一個 population 的功能,當你在定義 Schema 的時候指定了某個 field 是引用了另外一個 Schema ,那麼你在獲取 document 的時候就可使用 populate 方法讓 Mongoose 幫你經過引用 Schema 和 id 找到關聯的另外一個 document,而且用該 document 的內容替換掉原來引用字段的內容,使引用的 ducoment 使用起來就像是內嵌的 document 同樣方便。數組
首先,若是要使用這個功能,必須給你的「外鍵字段」定義 Mongoose 的「外鍵約束」(這裏借用關係型數據庫的術語,只是爲了幫助理解)。假設咱們有一個用戶的 Schema ,其中有一個字段是followings,保存用戶關注了的其餘用戶,相似微博。Mongoose 的 Schema 定義以下:mongoose
var mongoose = require('mongoose') , Schema = mongoose.Schema var UserSchema = Schema({ name : String, followings : [{ type: Schema.Types.ObjectId, ref: 'User' }] }); var User = mongoose.model('User', UserSchema);
而後咱們建立兩個 User 實例,而且先將其中之一保存進數據庫(爲了產生 _id ):函數
var lily = new User({name: 'lily'}) ,lucy = new User({name: 'lucy'}); lily.save(cb);
lily 保存成功後,咱們再在回調函數 cb 中保存 lucy ,不過這個時候假設 lucy 關注了 lily:ui
function cb(err) { if(err) throw err; lucy.followings.push(lily._id);// line 1 lucy.save(cb1); }
這樣就保存完成了。不過好像咱們沒用引用字段以前也是這麼保存的吧?有沒有更直接一點的?有,你其實能夠將 line 1 的語句改爲如下形式, Mongoose 也會自動幫你作內部解析的:code
lucy.followings.push(lily);
這樣看起來代碼就更接近天然語言了,有點ORM的味道。對象
固然,上面的例子可能對開發者來講沒有什麼太大的用處,那麼就來看看 population 在獲取 document 的時候能給咱們帶來什麼好處吧。排序
假設咱們如今要找到 lucy 的信息以及她所關注的用戶,咱們能夠這樣:開發
User.findOne({name: 'lucy'}).exec(cb2);
可是這樣拿出來的 lucy 的 followings 是一組存儲了 ObjectId 的數組,還得去一個個查找對應的用戶,多麻煩啊。因此這個時候用 population 就簡單多了,直接指定你想要 populate 哪一個引用字段:get
User.findOne({name: 'lucy'}).populate('followings').exec(cb2);
這樣的話,在回調函數 cb2 中你獲得的就是一個存儲了若干個 User 對象的數組了。
populate 方法能夠用在 document 上、 model 上或者是 query 對象上,這意味着你幾乎能夠在任何地方調用這個方法以填充你的引用字段。
固然,populate 方法在不一樣對象上參數不大同樣,可是都接收一個option的參數,你能夠用這些參數指定:
目前,Mongoose 只支持如下幾種引用字段的類型:
並且天然而然,引用 document 的主鍵類型必須和引用字段類型相對應。在生產環境中,推薦主鍵類型和引用類型都使用 ObjectId ,一是由於 ObjectId 不包含業務含義,二是 ObjectId 不大可能重複,三是由於 Mongoose 默認生成的主鍵類型就是 ObjectId ,能夠減小不少配置的操做。
更多信息請關注這裏。