Mongoose使用population建立關係連結例項說明

weixin_33716557發表於2016-04-27
引用文件:

基於Node.js專案實踐,構建可擴充套件的web應用(噹噹書籍地址)

Mongoose 使用之 Population

Mongoose API v4.4.13 .
版本資訊:"express": "~4.13.1","mongoose":"4.3.6"

MongoDB、Mongoose

MongoDB是NoSQL資料庫,易擴充套件,比傳統資料庫更適合處理大資料。Mongoose是基於Node.js、MongoDB的高階ORM類庫。連結資料庫簡單,不必每次開啟關閉資料庫。對於NoSql資料庫來說,資料庫中是不儲存關係資料的,並沒有主鍵、外來鍵約束之分,但是我們可以在應用層進行儲存,Mongoose提供的這一特性,名為population,允許我們使用不同集合來填充文件特定部分,個人理解感覺就像是通過外來鍵可以獲得外來鍵所在表中的資訊這樣的查詢效果。

在介紹population之前,先簡單介紹一下Mongoose的一些名詞:

Schema:一種以檔案形式儲存的資料庫模型骨架,不具備資料庫的操作能力。

Model:由Schema釋出生成的模型,具有抽象性和行為的資料庫操作對。

例項說明:

首先引入mongoose模組,連線資料庫

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');

連結資料庫之後要定義原型,原型是一個json格式的類,Mongoose的原型支援下面這些資料型別:

  • String
  • Number
  • Boolean
  • Buffer:node.js二進位制型別,多用於影像、PDF、檔案等;
  • Date:ISO標準格式化日期型別;
  • Array
  • Schema.Types.ObjectId:MongoDB中的一個典型24個字元,12位元組的十六進位制數字字串;
  • Schema.Type.Mixed:任何型別資料。

建立的例項場景為一個聊天室中可以有多名使用者。

建立使用者原型:

var UserSchema = Schema({
  _id:Number,
  name : String,
  sex:String
})
var User = mongoose.model('users', UserSchema);//將原型和方法編譯為一個模組,users也將是存入資料庫中的集合的名稱。

建立聊天室原型:

var RoomSchema = Schema({
  roomNumber:String,
  roomMember:[{
    type:Number, ref: 'users'
  }],
})
var Room = mongoose.model('rooms',RoomSchema);//將原型和方法編譯為一個模組

建立例項:

var lily = new User({'_id':1000,'name': 'lily','sex':'F'});
var lucy = new User({'_id':1001,'name':'lucy','sex':'F'});
var room = new Room({
  'roomNumber':'1',
  'roomMember':[lily._id,lucy._id]//此處所呼叫的必須為_id欄位,如果建立原型時未建立id欄位,則資料庫會自動生成Schema.Types.ObjectId型別的_id
});

將資料存入資料庫:

function callback(err,doc){
  if(err) throw err;
  console.log(doc);//返回的是存入資料庫中的記錄
};
lily.save(callback);
lucy.save(callback);
room.save(callback);

資料庫中查詢記錄

1094385-c76c07aeca3cdb0f.png
資料庫中的查詢記錄

population的使用
在查詢資料的而過程中使用population可以輸出相應的例項記錄

Room.findOne({roomNumber:'1'})
.populate('roomMember')
.exec(callback);

通過population查詢之後,在控制檯中列印的console.log(doc)如下圖所示:

1094385-a79eae57bd0f0a59.png

通過圖片我們可以看到在room原型中所ref的user原型中符合的資訊已經全部都輸出了,這樣就不用多集合查詢獲得資訊了,雖然各集合之間都沒有關係,但是我們通過使用population在應用層儲存它們,太感人了!
Demo地址:https://github.com/a67c/populateDemo

出現的錯誤提示及原因

 E11000 duplicate key error index: populateDemo.users.$_id_ dup key: { : 1000 }

出現了重複的鍵,由於使用者的_id是手動插入的,而非系統自動生成的ObjectedId(),所以如果再插入_id:1000,就會報此類錯誤。

Cast to ObjectId failed for value "XXX" at path "_id".

呼叫的參考值不是_id,按照例子來說就是在例項化時'roomMember':[lily._id,lucy._id]呼叫一定要是_id欄位!
小擴充套件

1、當我不需要獲得一條記錄的全部資訊時可以在populate中對於輸出的資訊做限制

Room.findOne({roomNumber: '1'})
.populate('roomMember','name')
.exec(callback);

在populate中新增User中的欄位name,那麼在輸出的過程中就會只顯示name和_id欄位。

ps:錯誤之處還請指出,多多指教

個人部落格:
進擊的程式茗

相關文章