SEE UPDATED EXAMPLE CODE @ BOTTOM
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)
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.
Heres what I have thus far:
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..
} )
}
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.
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.
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?
Thank you
Update
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
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
UPDATE
I figured maybe I could provide a more simplified but detailed example.
Heres the middleware module thats supposed to compare the pre(save)
and
post(save)
:
'use strict'
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)
} )
}
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