[英]Sharing data between Mongoose middleware methods pre save and post save
我在我當前的 NodeJS 項目中使用 Mongoose(順便說一句,這太棒了!),我有一個 MDB 集合,它將在不同的集合中存儲文檔的更改(基本上是一個存儲修改內容的更改日志)
我試圖實現的方法是創建一個函數來存儲文檔的 JSON 版本,這是通過pre('save')
鈎子完成的。 然后創建另一個鈎子,它通過post('save')
,以比較存儲在pre('save')
,並將其與文檔新數據進行比較。
這是我迄今為止所擁有的:
var origDocument
var testVar = 'Goodbye World'
module.exports = ( schema, options ) => {
schema.pre( 'save', function( next ) {
// Store the original value of the documents attrCache.Description value
origDocument = this.toJSON().attrCache.Description
// Change the testVar value to see if the change is reflected in post(save)
testVar = 'Hello World'
next()
} )
schema.post( 'save', function( ) {
// Attempt to compare the documents previous value of attrCache.Description, with the new value
console.log("BEFORE:", origDocument)
console.log("AFTER:", this.toJSON().attrCache.Description)
// Both of the above values are the same! >.<
console.log('post(save):',testVar) // result: post(save):Hello World
// But the above works just fine..
} )
}
我原本不認為這會奏效。 為了測試這兩個鈎子是否在同一范圍內執行,我在頁面頂部創建了一個名為testVar
的測試變量,其中包含一些任意值,然后在post(save)
鈎子中,檢索了testVar
,以及它的值修改在 post save hook 中看到了變量。
所以從那里開始,我只是將this.toJSON()
的值存儲在一個變量中,然后在 post(save) 掛鈎中,我試圖檢索該文檔的緩存版本,並將其與this.toJSON()
進行比較。 但是,看起來pre(save)
的文檔並不包含預修改的數據,它在更新后以某種方式具有文檔的值。
那么為什么我可以從pre(save)
鈎子中更新testVar
的值,而這種變化反映在post(save)
鈎子函數中,但我不能對文檔本身做同樣的事情?
我在這里嘗試做的事情甚至可能嗎? 如果是這樣,我做錯了什么? 如果沒有 - 我怎樣才能做到這一點?
謝謝
根據@Avraam 的建議,我嘗試通過JSON.stringify()
運行數據,然后通過pre(save)
掛鈎將其保存在內存中,然后在post(save)
執行相同操作,如下所示:
var origDocument
module.exports = ( schema, options ) => {
schema.pre( 'save', function( next ) {
origDocument = JSON.stringify( this.toJSON().attributes[1].value )
// Should store and output the CURRENT value as it was before the
// document update... but it displays the NEW value somehow
console.log( '[MIDDLEWARE] ORIGINAL value:', origDocument )
next()
} )
schema.post( 'save', function( ) {
var newDocument = JSON.stringify(this.toJSON().attributes[1].value)
console.log( '[MIDDLEWARE] UPDATED value:', newDocument )
} )
}
這是更新貓鼬文檔的腳本:
Asset.getAsset( '56d0819b655baf4a4a7f9cad' )
.then( assetDoc => {
// Display original value of attribute
console.log('[QUERY] ORIGINAL value:', assetDoc.attributes[1].value)
var updateNum = parseInt( assetDoc.__v )+1
assetDoc.attr('Description').set('Revision: ' + updateNum )
return assetDoc.save()
} )
.then(data => {
// Display the new value of the attribute
console.log('[QUERY] UPDATED value:', data.attributes[1].value)
//console.log('DONE')
})
.catch( err => console.error( 'ERROR:',err ) )
這是我運行新腳本時的控制台輸出:
[QUERY] ORIGINAL value: Revision: 67
[MIDDLEWARE] ORIGINAL value: "Revision: 68"
[MIDDLEWARE] UPDATED value: "Revision: 68"
[QUERY] UPDATED value: Revision: 68
如您所見, [QUERY] ORIGINAL值和[QUERY] UPDATED值表明存在更新。 但是[MIDDLEWARE]原始/更新值仍然相同......所以我仍然堅持為什么
我想也許我可以提供一個更簡單但更詳細的例子。
這是應該比較pre(save)
和
post(save)
: '使用嚴格'
import _ from 'moar-lodash'
import * as appRoot from 'app-root-path'
import Mongoose from 'mongoose'
import diff from 'deep-diff'
var originalDesc
module.exports = ( schema, options ) => {
schema.pre( 'save', function( next ) {
originalDesc = JSON.parse( JSON.stringify( this.toJSON() ) ).attributes[1].value
console.log( '[MIDDLEWARE ORIGINAL Desc]\n\t', originalDesc )
next()
} )
schema.post( 'save', function( ) {
var newDesc = JSON.parse( JSON.stringify( this.toJSON() ) ).attributes[1].value
console.log( '[MIDDLEWARE NEW Desc]\n\t', newDesc)
} )
}
然后是使用Asset
模型並更新Description
屬性的代碼......
'use strict'
import _ from 'moar-lodash'
import Promise from 'bluebird'
import Mongoose from 'mongoose'
import Async from 'async'
import Util from 'util'
import * as appRoot from 'app-root-path'
Mongoose.Promise = Promise
Mongoose.connect( appRoot.require('./dist/lib/config').database.connection )
const accountLib = appRoot.require('./dist/lib/account')
const models = require( '../models' )( Mongoose )
models.Asset.getAsset( '56d0819b655baf4a4a7f9cad' )
.then( assetDoc => {
var jqDoc = JSON.parse(JSON.stringify(assetDoc.toJSON()))
// Show the CURRENT description
console.log('[IN QUERY - Before Modify]\n\t', jqDoc.attributes[1].value)
assetDoc.attr('Description').set( 'Date-'+Date.now() )
return assetDoc.save()
} )
.then(data => {
// Just show the Description AFTER it was saved
console.log('[AFTER QUERY - AFTER Modify]\n\t', data.attributes[1].value)
})
.catch( err => console.error( 'ERROR:',err ) )
.finally( () => {
Mongoose.connection.close()
console.log('# Connection Closed')
})
[IN QUERY - Before Modify]
Date-1474915946697
[MIDDLEWARE ORIGINAL Desc]
Date-1474916372134
[MIDDLEWARE NEW Desc]
Date-1474916372134
[AFTER QUERY - AFTER Modify]
Date-1474916372134
# Connection Closed
好的,您問題的第一部分由 Avraam Mavridis 正確回答,因此我將只關注您在問題中的最后更新。
pre.save
實際上並不保存當前存在於數據庫中的實際文檔,而是將要保存的文檔,並包含對文檔所做的更改,即更新的文檔。
post.save
保存存儲在數據庫中的真實文檔,因此仍然是更新版本。 因此,在save
pre
和save
post
僅查看this
,您無法看到所做的更改。
現在,如果您想查看數據庫中存在的真實值,您需要在更改和保存之前從數據庫中獲取它,即在pre.save
。
var originalDesc module.exports = ( schema, options ) => { schema.pre( 'save', function( next ) { Asset.getAsset( '56d0819b655baf4a4a7f9cad' ) .then( assetDoc => { originalDesc = assetDoc.attributes[1].value; console.log( '[MIDDLEWARE ORIGINAL Desc]\\n\\t', originalDesc ) next() } ); } ); schema.post( 'save', function( ) { var newDesc = this.toJSON().attributes[1].value console.log( '[MIDDLEWARE NEW Desc]\\n\\t', newDesc) } ) }
schema.path('name').set(function (newVal) { this.originalDesc = this.Description; }); schema.pre('save', function (next) { console.log( '[MIDDLEWARE ORIGINAL Desc]\\n\\t', this.originalDesc ) next(); }) schema.post( 'save', function( ) { var newDesc = this.toJSON().attributes[1].value console.log( '[MIDDLEWARE NEW Desc]\\n\\t', newDesc) } )
希望這可以幫助。
origDocument
引用了this.toJSON()
並且當您調用console.log
,引用點已經更改的實際對象的值。 使用類似JSON.stringify
東西來比較這些值。
origDocument = JSON.stringify( this.toJSON() )
我認為你誤解了 pre/post 鈎子在貓鼬中是如何工作的。 當您抓取文檔時(正如您所做的那樣)並重新保存它。 它不會有文檔中最初的任何變量。 它將包含文檔中當前的任何內容。
所以,你正在這樣做:
我認為您想要做的是在您的架構上實現一個實例方法,您可以使用它來定義您想要的邏輯。 你會在調用 .save() 之前調用它(或者在你執行自己的邏輯之后使用它來調用 .save() )
例子:
schema.methods.createRevisionHistory= function(object, callback) {
// Do comparison logic between this. and object.
// modify document (this) accordingly
// this.save(function(err, doc) {
// if(err)
// return callback(err)
// callback(doc);
// })
};
希望這可以幫助
origDocument 有 this.toJSON 的引用,所以當 this.toJSON 在 post('save') origDocument 中改變時也會改變。 試試下面的代碼:
var origDocument
var testVar = 'Goodbye World'
module.exports = ( schema, options ) => {
schema.pre( 'save', function( next ) {
// Store the original value of the documents attrCache.Description value
origDocument = JSON.parse(JSON.strinigify(this.toJSON().attrCache.Description))
// Change the testVar value to see if the change is reflected in post(save)
testVar = 'Hello World'
next()
} )
schema.post( 'save', function( ) {
// Attempt to compare the documents previous value of attrCache.Description, with the new value
console.log("BEFORE:", origDocument)
console.log("AFTER:", this.toJSON().attrCache.Description)
// Both of the above values are the same! >.<
console.log('post(save):',testVar) // result: post(save):Hello World
// But the above works just fine..
} )
}
使用 JSON.parse(JSON.stringify()) 我清除了參考。
希望這可以幫助!!!
您可以使用另一個中間件,並將當前值臨時設置為未定義的屬性(因此它不會在save
調用時保存到數據庫中)。
例如
schema.post('init', function(doc) {
// when document is loaded we store copy of it to separate variable
// which will be later used for tracking changes
this._original = doc.toJSON({depopulate: true});
});
然后在 post save hook 中進行比較:
schema.post('save', function(doc) {
// do the diffing of revisions here
});
在我們的 API 中,我通過使用document.$locals
作為原始值的存儲位置解決了這個問題。 document.$locals
不會傳遞到數據庫,它會在中間件調用之間持久化。
post('find')
和post('findOne')
鈎子中:doc.$locals.originalValues = doc.toObject();
pre('save')
和post('save')
鈎子中:let changes = doc.getChanges()
, originalValues = doc.$locals.originalValues;
if (changes.$set) {
for (let key in changes.$set) {
_.set(result, key, originalValues[key]);
result[key] = originalValues[key]; // May be undefined
}
}
if (changes.$unset) {
for (let key in changes.$unset) {
_.set(result, key, originalValues[key]);
result[key] = originalValues[key]; // Should be defined
}
}
這些是代碼的相關部分。 還有很多錯誤檢查和邊緣情況檢測,但從根本上說,我們每次檢索時都會存儲原始文檔,因此可以將這些值與保存的數據進行比較。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.