【问题标题】:Mongoose pre findOneAndUpdate hook issuesMongoose pre findOneAndUpdate 钩子问题
【发布时间】:2015-10-27 17:11:30
【问题描述】:

我正在尝试更新 pre hook 上的计数。问题是,据我所知,由于某种未知原因,findOneAndUpdate 挂钩无法访问该文档。

我想这样做:

source.pre('findOneAndUpdate', function (next) {
  console.log('------------->>>>>> findOneAndUpdate: ');
  this.objects = this.objects || [];
  this.people = this.people || [];
  this.events = this.events || [];

  this.objectCount = this.objects.length;
  this.peopleCount = this.people.length;
  this.eventCount = this.events.length;

  next();
});

但由于某种原因,钩子中的this 不是文档,它是一个看起来几乎没用的查询对象。

我错过了什么? 如何使用 pre hook 来更新 findOneAndUpdate 的计数?

【问题讨论】:

    标签: mongoose


    【解决方案1】:

    documentation 声明:

    查询中间件与文档中间件有一个微妙但重要的区别:在文档中间件中,this 指的是正在更新的文档。在查询中间件中,mongoose 不一定引用正在更新的文档,因此this 指的是 query 对象,而不是正在更新的文档。

    更新操作通常会更新仅存在于数据库中的文档(它告诉 MongoDB 服务器:“找到文档 X 并将属性 X 设置为值 Z”),因此完整的文档不是t 可用于 Mongoose,因此您无法更新计数(这需要访问至少要确定其长度的数组)。

    顺便说一句:为什么在架构中仍然需要单独的 *Count 属性?如果要查询匹配一定大小的数组,可以直接对数组使用$size操作符。

    如果您确实需要 count 属性,那么对于每次更新,您需要跟踪您对每个数组所做的更改次数(根据添加/删除的项目数)并使用 $inc操作员来调整计数。

    【讨论】:

    • 计数在那里,所以我可以返回带有find 的完整项目列表并排除数组,因为当我返回完整列表时我不想要详细信息。那么如何自动更新计数呢?对我来说,无法访问文档的 pre hook 是毫无意义的。
    • @Justin808 如果要返回数组大小,请考虑使用an aggregation。如果要更新计数,您需要首先从数据库中检索完整文档,更新值,更新计数(或为此使用 document 中间件,例如 pre('save')),然后保存它返回到数据库。由于解释的原因,您不能在更新中执行此操作。
    • 我想我不明白$size 的事情。我现在正在做一个SourceModel.find({treeId: treeId}, '-objects -people -events', callback)。在哪里添加$size 以返回objectspeopleevents 数组的大小?
    • @Justin808 它必须是一个单独的(聚合)查询。请参阅我之前评论中的链接。如果您的阵列不是很大,我会认真考虑将它们拉入以确定它们的大小。根据具体情况,您可以使用更新操作使其工作;查看我的编辑。
    【解决方案2】:

    你可以那样做 ->

    source.pre('findOneAndUpdate', function (next) {
        console.log('------------->>>>>> findOneAndUpdate: ');
        this._update.$set.objects = [];
        this._update.$set.people = [];
        this._update.$set.events =  [];
        next();
    });
    

    注意 _update.$set 因为在上下文中“this”将是一个查询。因此,您可以轻松添加任何您想要的内容!

    【讨论】:

    • 我在其他问题上看到过类似的答案,但这实际上是受支持还是只是一种破解?
    • @T.Okahara 看起来像直接访问 _update 可能有点笨拙,但在当前 API 中有 Query.prototype.getUpdate 和 Query.prototype.setUpdate 这看起来像是实现此目标的受支持方式。
    【解决方案3】:

    我在使用 updateOne 方法时遇到了类似的问题,并且还打算使用 updateOne 预挂钩在保存到数据库之前进行间歇性更新。找不到让它工作的方法。我最终使用了 findOneAndUpdate 预挂钩并在其中执行了 updateOne。

    schema.pre('findOneAndUpdate', async function(next){ 
         const schema = this;
         const { newUpdate } = schema.getUpdate();
         const queryConditions = schema._condition
    
         if(newUpdate){
           //some mutation magic
           await schema.updateOne(queryConditions, {newUpdate:"modified data"}); 
           next()
         }
         next()
    })
    

    【讨论】:

      【解决方案4】:

      另一种解决方案是使用中间件上的官方 MongoDB 文档。他们解释了为什么“this”不是指文档本身。你可以在这个意义上尝试一些东西:

         source.pre('findOneAndUpdate', async function(next) {
           const docToUpdate = await this.model.findOne(this.getFilter());
              //modify the appropriate objects
           docToUpdate.save(function(err) {
             if(!err) {
               console.log("Document Updated");
              }
           });
          console.log(docToUpdate); 
           // The document that `findOneAndUpdate()` will modify
             next();   
           });
      

      【讨论】:

      • 我只想提一下 this.getQuery() 已被弃用,取而代之的是 this.getFilter()。
      【解决方案5】:

      这对我有用

      SCHEMA.pre('findOneAndUpdate', function(next){
         this._update.yourNestedElement
         next();
      });
      

      【讨论】:

        【解决方案6】:
            schema.pre(['findOneAndUpdate'], async function(next) {
                try {
                    const type = this.get('type')
                    const query = this.getQuery()
        
                    const doc =  await this.findOne(query)
        
                    if (type) {
                        this.set('type', doc.type)
                    }
        
                    next()
                } catch (e) {
                    next(new BaseError(e))
                }
            })
        

        【讨论】:

          猜你喜欢
          • 2019-07-01
          • 2017-05-06
          • 2016-12-15
          • 2018-11-17
          • 2019-12-26
          • 1970-01-01
          • 2021-03-03
          • 1970-01-01
          • 2019-07-26
          相关资源
          最近更新 更多