在保存前和保存后的 Mongoose 中间件方法之间共享数据 [英] Sharing data between Mongoose middleware methods pre save and post save
问题描述
我在当前的 NodeJS 项目中使用 Mongoose(顺便说一句,这太棒了!),我有一个 MDB 集合,用于将文档的更改存储在不同的集合中(基本上是一个变更日志存储修改的内容)
I'm using Mongoose (which is awesome btw!) in my current NodeJS projects, and I have a MDB collection thats going to store the changes of documents in a different collection (Basically a changelog storing what was modified)
我试图实现的方法是创建一个函数来存储文档的 JSON 版本,这是通过 pre('save')
钩子完成的.然后创建另一个钩子,通过 post('save')
执行,将存储在 pre('save')
中的数据与新的文档进行比较数据.
How I'm trying to accomplish that is create a function that stores a JSON version of the document, which is done via the pre('save')
hook. Then create another hook, which gets executed via post('save')
, to compare the data stored in pre('save')
, and compare it with the documents new data.
这是我目前所拥有的:
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 钩子中看到了该变量的值修改.
I originally didn't think this would work. To test that the two hooks get executed in the same scope, I created a test variable at the top of the page called testVar
with some arbitrary value, then in the post(save)
hook, retrieved the testVar
, and the value modification of that variable was seen in the post save hook.
因此,我只是将 this.toJSON()
的值存储在一个变量中,然后在 post(save) 挂钩中,我试图检索此文档的缓存版本,并将其与 this.toJSON()
进行比较.但是,它看起来不像 pre(save)
中的文档不包含预修改的数据,它以某种方式具有文档的值 after 更新.
So from there, I just stored the value of this.toJSON()
in a variable, then in the post(save) hook, I am trying to retrieve the cached version of this document, and compare it to this.toJSON()
. However, it doesn't look like the document from the pre(save)
doesnt hold the pre-modified data, it somehow has the value of the document after it was updated.
那么为什么我可以从 pre(save)
钩子中更新 testVar
的值,并且该更改反映在 post(save)
钩子函数,但我不能对文档本身做同样的事情?
So why can I update the value of testVar
from within a pre(save)
hook, and that change is reflected from a post(save)
hook function, but I cant do the same thing with the document itself?
我在这里尝试做的事情有可能吗?如果是这样,我做错了什么?如果没有 - 我怎样才能做到这一点?
Is what im trying to do here even possible? If so, what am I doing wrong? If not - How can I accomplish this?
谢谢
根据@Avraam 的建议,我尝试通过 JSON.stringify()
运行数据,然后通过 pre(save)
钩子将数据保存在内存中,然后在 post(save)
中做同样的事情,就像这样:
Per the advice from @Avraam, I tried to run the data through JSON.stringify()
before saving it in memory via the pre(save)
hook, then do the same in the post(save)
, like so:
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 )
} )
}
这是更新猫鼬文档的脚本:
And here's the script that updates the mongoose document:
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 ) )
这是我运行新脚本时的控制台输出:
Heres the console output when I run the New script:
[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] 原始/更新值仍然相同......所以我仍然不知道为什么
As you can see, the [QUERY] ORIGINAL value and the [QUERY] UPDATED values show that there was an update. But the [MIDDLEWARE] original/updated values are still the same... So im still stuck as to why
我想也许我可以提供一个更简单但更详细的例子.
I figured maybe I could provide a more simplified but detailed example.
这是应该比较 pre(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
属性的代码...
Then heres the the code that uses the Asset
model and updates the Description
attribute...
'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 正确回答了您问题的第一部分所以我只会关注你在问题中的最后更新.
Ok, The first part of your question is correctly answered by Avraam Mavridis so I will only focus on your last update in the question.
pre.save
实际上并不保存当前存在于数据库中的实际文档,而是将要保存的文档,并且包含对文档所做的更改,即更新的文档.
pre.save
actually doesn't hold the actual document that currently exixts in the database, instead it is the document which is going to be saved, and contains the changes done to the document, i.e. the updated document.
post.save
保存存储在数据库中的真实文档,因此仍然是更新的版本.因此,您无法在 pre
和 post
save
中查看仅查看 this
所做的更改.
post.save
holds the real document that is stored in the database, hence still the updated version. So you can not see the change that is done just looking at this
in both pre
and post
save
.
现在,如果您想查看数据库中存在的真实值,您需要在更改和保存之前从数据库中获取它,即在 pre.save
中.
Now if you want to see the real values that existed in the database you need to fetch it from database before it is changed and saved, i.e. in pre.save
.
<小时>一种方法是简单地从数据库中查询文档
One way you could do this is simply query the document from database
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)
} )
}
<小时>还有一种使用自定义设置器的替代方法,并且已经有一个很好的此处的答案,但这需要设置每个属性的自定义设置器
There is an alternative way than this using custom setter, and there is already a good answer here, but this would require to set a custom setter for each property
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)
} )
希望这会有所帮助.
这篇关于在保存前和保存后的 Mongoose 中间件方法之间共享数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!