mongoose:设置双向引用

我正在开发一个Express + Mongoose Web应用程序,它有许多相互依赖的模型。 除了我可能没有正确devise我的数据的可能性,我期待着找出在两个彼此相关的对象之间设置引用的最佳方法。

我知道在我的Schema obj中,如果我想要一个Schema来引用另一个Schema,我添加referenceId: { type: Schema.Types.ObjectId, ref: 'ModelName' },作为一个属性。 到目前为止,创build模型时,我一直在设置这个属性为我想引用的id 。 例如: obj.referenceId = someReferenceId; obj.save(...) obj.referenceId = someReferenceId; obj.save(...)

但是,如果我有两个独立的模式,但是每个模式都有一个相互参照的话呢? 什么是设置这些最好的方法?

现在我正在做下面的代码,但是代码看起来很乱:

 objectASchema = Schema({ objectBReference: { type: Schema.Types.ObjectId, ref: 'ObjectB' }, }) mongoose.model('ObjectA', objectASchema); objectBSchema = Schema({ objectAReference: { type: Schema.Types.ObjectId, ref: 'ObjectA' }, }) mongoose.model('ObjectB', objectBSchema); // in a route/controller, and assuming we have an Object B created // but you can see that if I don't have that, it gets messier ObjectA.create(..., function(err, objectA) { objectA.objectBReference = objectBReferenceId; objectA.save(function(err) { ... ObjectB.findById({_id: objectBReferenceId}, function(err, objectB) { objectB.objectAReference = objectA._id; objectB.save(function(err) { if (!err) { // success! we're done here... } }); }) }); }) 

我有意避免在这种情况下embedded,因为在我的应用程序,我正在假设,我需要单独查询这些对象,而无需从任何一方加载数据。

我的用例类似于ProductReviewUser模型,其中每个引用另一个,但不一定embedded其他。 查询可以是这样的:获取该产品的所有评论,或来自该用户的所有评论。 这意味着评论不能embedded到用户或产品中。

使用MongooseJS,你可以在本地创build它们两个,关联它们,然后使用promise(这使用原生的Promise对象,但是一个库将工作)并行地保存到数据库:

 var objectA = new ObjectA(); var objectB = new ObjectB(); objectA.objectBReference = objectB; objectB.objectAReference = objectA; Promise.all([ objectA.save(), objectB.save() ]).then(function(savedObjects) { // Do something to celebrate? }).catch(function(err) { // one or both errored }); 

更新:如果需要,也可以使用嵌套保存。 关键在于ID是在本地生成的,可以与其他文档关联,而不必先保存它们。

 var objectA = new ObjectA(); var objectB = new ObjectB(); objectA.objectBReference = objectB; objectB.objectAReference = objectA; objectA.save(function (err, objA) { if (err) { ... } objectB.save(function (err, objB) { if (err) { ... } // Do something to celebrate? }); });