猫鼬:设置双向引用

时间:2015-07-15 17:47:13

标签: node.js mongodb mongoose

我正在使用Express + Mongoose网络应用程序,该应用程序具有许多相互依赖的模型。除非我可能没有正确设计我的数据,否则我希望找出在两个彼此相关的对象之间设置引用的最佳方法。

我知道在我的Schema obj中,如果我想让Schema引用另一个Schema,我会添加referenceId: { type: Schema.Types.ObjectId, ref: 'ModelName' },作为属性。到目前为止,在创建模型时,我已将此属性设置为我想要引用的id。例如: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...
                }
            });
        })
    });
})

我故意避免嵌入这种情况,因为在我的应用程序中,我在假设我需要单独查询这些对象而不必从其中加载数据的情况下运行。

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

1 个答案:

答案 0 :(得分:6)

使用MongooseJS,您可以在本地创建它们,关联它们,然后使用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?
  });
});