我在当前的NodeJS项目中使用Mongoose(这真棒!),我有一个MDB集合,可以将文档的更改存储在不同的集合中(基本上是 changelog 存储被修改的内容
我是如何实现这一目标的,创建一个存储文档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)
钩子中检索{{1在保存后的挂钩中看到变量的值修改。
所以,从那里,我只是将testVar
的值存储在变量中,然后在post(save)钩子中,我试图检索此文档的缓存版本,并将其与{{1 }}。但是,看起来this.toJSON()
中的文档并不包含预先修改过的数据,它在某种程度上具有文档之后更新后的值。
那么为什么我可以在this.toJSON()
钩子中更新pre(save)
的值,并且该更改反映在testVar
钩子函数中,但是我不能对它做同样的事情。记录本身?
我试图在这里做什么甚至可能?如果是这样,我做错了什么?如果不是 - 我怎么能做到这一点?
谢谢
根据@Avraam的建议,我尝试通过pre(save)
运行数据,然后通过post(save)
挂钩将其保存到内存中,然后在JSON.stringify()
中执行相同操作,就像这样:
pre(save)
这是更新mongoose文档的脚本:
post(save)
当我运行New脚本时,继承控制台输出:
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 )
} )
}
如您所见, [QUERY] ORIGINAL 值和 [QUERY] UPDATED 值表示存在更新。但是 [MIDDLEWARE] 原始/更新的值仍然是相同的...所以我仍然坚持为什么
我想也许我可以提供一个更简化但更详细的例子。
继承了应该比较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
:
&#39;使用严格的&#39;
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
答案 0 :(得分:3)
好的,Avraam Mavridis正确回答了您问题的第一部分 所以我只关注你在问题上的最后一次更新。
pre.save
实际不保存当前在数据库中存在的实际文档,而不是将要保存的文档,并包含对文件,即更新的文件。
post.save
包含存储在数据库中的真实文档,因此仍然是更新版本。因此,您只能在this
和pre
post
中查看save
时看到的更改。
现在,如果您想要查看数据库中存在的实际值,您需要在更改和保存之前从数据库中获取它,即在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)
} )
}
<小时/> 除了使用自定义setter之外,还有一种替代方法,并且已经有了很好的answer here,但这需要为每个属性设置自定义setter
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)
} )
希望这有帮助。
答案 1 :(得分:0)
origDocument
引用了this.toJSON()
以及您调用console.log
参考点已经更改的实际对象的值的那一刻。使用类似JSON.stringify
的内容来比较值。
origDocument = JSON.stringify( this.toJSON() )
答案 2 :(得分:0)
我认为你误解了前/后钩子在mongoose中是如何工作的。当您抓取文档(正如您所做)并重新保存它时。它不会具有文档中最初的任何变量。它将包含文档中当前的任何内容。
所以,你这样做:
我认为你想要做的是在你的架构上实现一个实例方法,你可以用它来定义你想要的逻辑。你可以在调用.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);
// })
};
希望这有帮助
答案 3 :(得分:0)
origDocument有this.toJSON的引用,所以当post.toJSON在post(&#39; save&#39;)中更改时,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())我已经清除了引用。
希望这有帮助!!!
答案 4 :(得分:0)
您可以使用另一个中间件,并暂时将当前值设置为未定义的属性(因此在save
调用时不会将其保存到数据库)。
E.g。
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
});
答案 5 :(得分:0)
在我们的 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
}
}
那些是代码的相关部分。还有很多错误检查和边缘情况检测,但从根本上说,我们每次检索时都会存储原始文档,因此可以将这些值与保存的数据进行比较。