mongoose再認識(二)

在開發中,除了使用mongoose進行一些基本的操做外,就是一些技巧的使用。node

文章接續mongoose再認識(一),下文中使用代碼可參考這篇文章中的。git

虛擬字段

虛擬字段,從字面意思就能夠明白,它不是真正的字段,不存在與數據庫中,可是當使用model實例查詢時,卻能夠靈活的運用這個字段。github

注:這個特性是mongoose本身的,與mongo無關。shell

...
// 添加了一個虛擬的fullname字段
// get fullname
UserSchema
  .virtual('fullname')
  .get(() => this.firstname + ' ' + this.lastname)
// set fullname
UserSchema
  .virtual('fullname')
  .set((name) => let arr = name.split(' '), this.firstname = arr[0], this.lastname = arr[1] )

// read
UserModel
  .find({})
  .exec()
  .then(doc => {
    console.log(doc[0])
  })

查詢的結果以下:數據庫

{ _id: 5c1dc7248aaf9c2c80fee915,
  firstname: '東坡',
  lastname: '蘇',
  __v: 0 }

那麼,如何獲取到結果fullname呢?mongoose

能夠經過doc[0].fullname來獲取。函數

如何對數據進行保存呢?代碼以下:post

// 模擬AJAX請求保存數據
let person2 = new UserModel()
person2.fullname = '白 李'

person2
  .save()
  .then(doc => console.log(doc))
  .catch(err => console.log(err))

返回結果:this

{ _id: 5c1dd7ef535df51980e9fd98,
  firstname: '白',
  lastname: '李',
  __v: 0 }

這樣,在開發的過程當中,就不用擔憂由於字段不匹配而須要修改數據庫的問題。這也是它存在的意義。prototype

有興趣的同窗可參考node club中對user.js中用戶的分級,不須要在創建一個字段用來保存用戶的等級,能夠用virtual Type經過socre計算來得出來。

在Schema定義一些Model實例經常使用的方法

熟悉mongoose的原理的都知道,Model的構造函數是在Schema實例的基礎上創造出來的。因此,對於頻繁操做的Model實例方法,能夠在Schema的實例上進行定義(具體的可參考JavaScript的prototype)。

在一個Schema中常常會帶有updateAtcreateAt這樣的字段,一般的狀況下,會給它們一個默認的值。userSchema代碼修改以下:

let UserSchema = new mongoose.Schema({
  firstname: String,
  lastname: String,
  createAt: {
    type: Date,
    default: Date.now
  },
  updateAt: {
    type: Date,
    default: Date.now
  }
})

在開發中,開發者每每不會手動的處理它們,可是對於跟蹤記錄一個數據來講又很必要,也不容許用對這些數據任意的修改。那麼,應該如何操做它纔是最好的呢?

固然,最好就是在執行post請求的時候,會有一些方法會根據必定機制自動保存。

而mongoose就存在這樣的機制,能夠在Schema的實例上添加pre的方法,代碼以下:

UserSchema.pre('save', function(next) {
  let now = Date.now()
  this.updateAt = now;

  if (!this.createAt) this.createAt = now;
  next()
})

模擬AJAX請求保存數據:

let person3 = new UserModel()
person3.fullname = '甫 杜'

person3
  .save()
  .then(doc => console.log(doc))
  .catch(err => console.log(err))

返回結果:

{ _id: 5c1e006204bad42224374aea,
  createAt: 2018-12-22T09:14:10.862Z,
  updateAt: 2018-12-22T09:14:10.877Z,
  firstname: '甫',
  lastname: '杜',
  __v: 0 }

這個覺過並不能說明問題,它是Schema定義時和pre方法共同做用的結果。

嘗試更新數據來驗證定義的方法,代碼以下:

UserModel.findOne({
  lastname: '杜'
})
.exec()
.then(function(doc) {
  doc.lastname = '杜'
  doc.firstname = '甫'

  doc.save()
  .then(doc => {
    console.log(doc)
  })
  .catch(err => {
    console.error(err)
  })
})
.catch(err => console.log(err))

返回結果:

{ _id: 5c1e006204bad42224374aea,
  createAt: 2018-12-22T09:14:10.862Z,
  updateAt: 2018-12-22T09:15:04.398Z,
  firstname: '牧',
  lastname: '杜',
  __v: 0 }

這裏,咱們使用save對數據進行更新,固然這對於跟蹤用戶的操做行爲頗有好處,可是並非全部的數據都須要的,而對於哪些不須要的,仍是能夠考慮使用findOneAndUpdate,updae,updateMany的。

細心的同窗會發現,其實它和shell命令的db.users.insert({})相似,user.save({})是插入一條數據,然後者則能夠插入多條數據。

注:在使用操做數據庫中的數據時必定要注意,要操做的時user.find()user.findOne()返回的一整條數據,若是是實例化了一個UserModel,則會形成數據庫中的數據丟失。

mongoose系列文章