我有一个模型,我们称之为它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 模型并更新它,但这给了我两个问题。它不会更新新的客户端文档(因为它在技术上尚不可查询)并且如果帐户创建失败,它仍会创建客户端。
很抱歉这个问题很长,我感谢任何反馈或建议来解决这个问题或实现我的目标的不同方法。如果你做到了这一步,感谢阅读!