Mongoose-modified-at 時間自動記錄外掛介紹

Barrior發表於2019-10-28

Mongoose-modified-at 是一款自動更新欄位變化時間並記錄到資料庫中的 Mongoose 外掛,類似 Mongoose 自帶的 timestamps 功能。

使用場景

讓我們考慮一個場景,我們有個文章釋出與展示的需求,資料模型如下。

const schema = new mongoose.Schema({
  // 文章標題
  title: String,
  // 是否為草稿
  is_draft: Boolean,
  // 是否推薦
  is_recommended: Boolean,
  // 更多欄位...
})
複製程式碼

當我們在展示最新文章列表時,應該是以文章第一次釋出的時間倒序展示,因為文章可以存為草稿,多次編輯,所以不能用 Mongoose 提供的 createdAtupdatedAt 作為第一次釋出的時間,正確的做法是在每次文章建立或更新時,確定使用者是釋出文章而不是存為草稿,然後記錄此次時間,用該時間作為第一次釋出的時間。

要實現該功能我們需要在程式碼邏輯層進行處理,這樣可行不過有點耦合,或者自己封裝一個 Mongoose 中介軟體來做這件事,不過現在你可以把這件事交給一個經受測試、API 優雅的外掛 ModifiedAt 來處理。

首先安裝外掛。

npm install mongoose-modified-at --save
複製程式碼

然後在 Schema 初始化時做簡單的配置即可,如下。

import modifiedAt from 'mongoose-modified-at'

// 在 mongoose.model 呼叫之前
schema.plugin(modifiedAt, {
  // 函式名將作為欄位名寫入資料庫
  publishedAt(doc) {
    // 當函式返回值為 true 時,則記錄該時間
    return !doc.is_draft
  },
  // 推薦文章也是如此
  recommendedAt(doc) {
    return doc.is_recommended
  },
})

const Article = mongoose.model('Article', schema)
複製程式碼

當文件儲存或更新攜帶著 is_draft 欄位並且值為 false 時,外掛就會記錄此次時間到你宣告的 publishedAt 欄位上一起寫入資料庫。

示例如下:

await Article.create({
  title: 'Document Title',
  is_draft: false,
  is_recommended: true,
  // 更多欄位...
})
複製程式碼

結果如下(資料庫):

{
  "title": "Document Title",
  "is_draft": false,
  "is_recommended": true,
  "publishedAt": ISODate("2019-09-27T03:11:07.880Z"),
  "recommendedAt": ISODate("2019-09-27T03:11:07.880Z"),
  // 更多欄位...
}
複製程式碼

附加案例

作為漸進式專案,我們的開發一般也是漸進式的,雖然我們會不自覺地超前考慮,但是還是不能完全考慮到未來需求的變化,假如我們對某個專案的功能已經完成並穩定上線了,後來比如我們需要做資料統計分析的工作,這項工作的分析維度對時間的精度要求比較高,所以要是我們在開發時並沒有考慮到要新增這些時間欄位(因為可能對業務不是必須的),而現在需要加上這些欄位,要是去原來的程式碼基礎上改動新增,如果改動的地方少還好,如果有完善的測試用例還好,否則這也許會改的心驚膽戰,因為你需要確保每一處改動不會產生錯誤影響。所以此時,使用無侵入式的中介軟體外掛 ModifiedAt 那就省心很多了,只需在模型出口簡單配置,無需改動邏輯層程式碼,即可實現剛剛想要的功能。

API介紹

上面是 ModifiedAt 的富 API 形式,即物件格式,全部引數選項如下。

schema.plugin(modifiedAt, {
  // 設定監聽欄位
  fields: ['name', 'status', 'another'],
  // 設定字尾
  suffix: '_your_suffix',
  // 設定路徑預設行為
  select: true,
  // 自定義欄位
  customField(doc) {
    // 做一些你想做的事,然後返回 Boolean 值,告訴外掛是否記錄時間
  },
})
複製程式碼

? 引數解釋:

  • fields: 設定監聽欄位,在文件建立或更新時,如果存在被監聽的欄位,則自動以 欄位名 + 字尾 的形式作為欄位,並記錄此次更新時間到該欄位上。可選,Array 型別。
  • suffix: 設定字尾,預設值為 _modifiedAt。可選,String 型別。
  • select: 設定路徑預設行為,預設為 true參考 Mongoose 文件。可選,Boolean 型別。
  • customField: 自定義欄位,此欄位不會加字尾,以函式形式新增到引數中,用於自定義功能,函式接收唯一文件引數,當函式返回值為真值時,則記錄此次時間到該欄位上。

簡化API

? 為了增加 API 的簡潔易用同時避免過度過載,ModifiedAt 只增加了一種簡化傳參格式,如下。

schema.plugin(modifiedAt, ['name', 'status'])
複製程式碼

意思是將 fields 選項提取出來作為引數,寫入資料庫的結果如下。

{
  "name": "Tom",
  "status": 1,
  "name_modifiedAt": ISODate("2019-09-27T03:13:17.888Z"),
  "status_modifiedAt": ISODate("2019-09-27T03:13:17.888Z"),
}
複製程式碼

支援非同步

你需要 Node.js 版本支援 async/await 即可。

import P from 'bluebird'

const petSchema = new mongoose.Schema({
  name: String,
  age: Number,
  sex: String,
  // 1:表示採購中,2:已購買,3:已售出
  status: Number,
})

petSchema.plugin(modifiedAt, {
  // 記錄購買於哪時
  async boughtAt(doc) {
    // 延時 1s
    await P.delay(1000)
    return doc.status === 2
  },
  // 記錄售出於哪時
  soldAt(doc) {
    return doc.status === 3
  },
})
複製程式碼

支援 Mongoose 4.x

如果你現在使用的是 Mongoose 4.x,那麼你需要使用外掛 1.x 版本,文件可在這裡檢視

npm install mongoose-modified-at@1 --save
複製程式碼

“100%”測試覆蓋率

29 個測試用例,777 行測試程式碼,“100%” 測試覆蓋率。

Mongoose-modified-at 時間自動記錄外掛介紹

細節

更多細節處理請移步至 GitHub 文件,這裡

最後

1、支援一下,煩請點個 Star 吧,貢獻就點個 Fork 吧 ?

2、本文同步發表於凹凸實驗室部落格或微信公眾號,歡迎關注我們,麼麼噠 ?

Mongoose-modified-at 時間自動記錄外掛介紹

相關文章