微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在猫鼬中发布中间件没有雾化操作?即使调用 next(err) 仍然创建文档

如何解决在猫鼬中发布中间件没有雾化操作?即使调用 next(err) 仍然创建文档

我有一个模型,我们称之为 Client,我还有另一个模型,称为 Accounts。它们来自不同的集合,一个客户可以有许多不同的帐户。我在客户文档中引用帐户,并从帐户文档中引用回客户。

const Client = new mongoose.Schema({
    accounts: [{
          type:mongoose.ObjectId,ref: 'Accounts',}],other....
})

const Accounts = new mongoose.Schema({
    name:String,clientID: mongoose.ObjectId
})

所以我们可以看到它们相互引用。我这样做是为了在请求客户信息时轻松访问填充帐户等。

我想做的是当我创建一个新客户端时,我还想创建一个新的认帐户并在 accounts 数组中引用它。我在创建新客户时尝试使用 pre hook 来创建新帐户,但是这不会使用新创建的 account doc _id 更新 Client Account 数组。我试过使用 this.update()

Client.pre('save',async function(next,args){
  if(this.isNew){
    await Accounts.create({clientID:this._id})
        .then(async doc=>{
            console.log(doc) // this logs my account doc just fine,which means it got created
            await this.update($push:{accounts:doc._id) // this doesnt seem to do anything
        })
        .catch(err=>next(err)
  }
  next()
}

所以 pre hook 几乎完成了我想要它做的事情,但是我想不出一种方法来使用新创建的 Account 文档中的信息更新我新创建的 Client 文档。它创建客户文档,并创建帐户文档。它的美妙之处在于,如果我在创建帐户文档时出错,那么由于它被原子化了,所以不会创建客户端。但可惜,没有更新的 accounts 数组...

因此,我尝试将其放入 post hook。

Client.pre('save',async function(doc,next){
    await Accounts.create({clientID:doc._id})
        .then(async acc=>{
           await doc.update({$push:{accounts:[acc._id]}}) 
        }).catch(err=>next(err)
}

嘿!这有效!......有点......我可以创建一个创建帐户文档的客户文档,然后更新客户端以在其accounts数组中包含帐户_id。

但是!!!我使用这种方法的问题是它似乎没有将操作原子化。因此,如果我故意使帐户创建失败(例如通过向它传递一个非 ObjectID 参数),那么它会调用 next(err),它在我的 http 请求中正确返回错误消息,甚至说操作失败。但是在我的数据库中,客户端文档仍然被创建,不像在它停止整个操作的前钩子中,在后钩子中它不会“撤消”客户端的创建。

总结和解决方

基本上我需要一种方法来更新它的 pre.('save') 钩子内的全新文档,以便它将存储我在钩子内处理的任何更改的数据。

如果我使用 post hook 来更新新文档,或者某种方式来保证操作的原子化。

我尝试过的其他事情:

我还尝试在创建 Account 文档后在 pre 钩子中使用 save() ,但这导致循环最大化文档内存,因为它刚刚成为递归

我尝试在 Accounts 模型上使用 pre-hook,这样它就会引用回 Client 模型并更新它,但这给我带来了两个问题。它不会更新新的客户端文档(因为它在技术上尚不可查询)并且如果帐户创建失败,它仍会创建客户端。

很抱歉问了这么长的问题,我感谢任何反馈或建议来解决这个问题或不同的方法来实现我的目标。如果你做到了这一点,感谢阅读!

解决方法

我的问题由几个问题组成,但我想发布解决方案。

虽然我仍然不知道如何保证 post hook 中的错误会使整个操作以原子方式运行,但解决方案非常简单。

在 pre 钩子内部,要修改帐户数组,我只需要 push() 到其中,无需尝试使用 this.set 或 this.update 或任何其他实际查询,只需直接修改 this

{
  //inside Client pre hook
  //create account doc
 await Accounts.create(...).then(doc=>{
      this.accounts.push(doc._id)
    }).catch(err=>next(err)
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。