在保存前和保存后的 Mongoose 中间件方法之间共享数据 [英] Sharing data between Mongoose middleware methods pre save and post save

查看:37
本文介绍了在保存前和保存后的 Mongoose 中间件方法之间共享数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在当前的 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 保存存储在数据库中的真实文档,因此仍然是更新的版本.因此,您无法在 prepost 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆