0

我有一个模型,我们称之为它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数组中引用它。我在创建新客户端以创建新帐户时尝试使用预挂钩,但是这不会account使用新创建的Account文档 _id 更新客户端数组。我试过使用 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 钩子几乎完成了我想要它做的事情,但是我想不出一种方法来使用新创建的 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 请求中调用 which 正确返回错误消息,甚至说操作失败。但是在我的数据库中,仍然创建了客户端文档,这与它停止整个操作的 pre-hook 不同,在 post hook 中它不会“撤消”客户端的创建。

总结和解决方案

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

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

我尝试过的其他事情:

在创建帐户文档后,我还尝试在 pre 钩子中使用 save() ,但这会导致循环最大化文档内存,因为它只是变得递归

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

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

4

1 回答 1

0

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

虽然我仍然不知道如何保证 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)
}
于 2021-03-26T18:00:23.050 回答