0

这是一个架构问题。我有这样的模型:

var foo = new mongoose.Schema({
  name: String,
  bars: [{type: ObjectId, ref: 'Bar'}]
});
var FooModel = mongoose.model('Foo', foo);

var bar = new mongoose.Schema({
  foobar: String
});
var BarModel = mongoose.model('Bar', bar);

然后我想实现一个这样的方便方法:

BarModel.methods.addFoo = function(foo) {
  foo.bars = foo.bars || []; // Side note, is this something I should check here?
  foo.bars.push(this.id);

  // Here's the line I'm wondering about... Should I include the line below?
  foo.save();
}

我看到的最大问题是,如果我确实包含了,foo.save()那么我应该传入一个回调,addFoo这样我就可以避免异步操作的问题。我认为这不是可取的。但我也认为包含它会很好,因为addFoo在它被保存之前还没有真正“添加Foo”......我是否打破了任何设计最佳实践?

4

2 回答 2

1

foo.bars = foo.bars || []; // 旁注,这是我应该在这里检查的吗?

不,猫鼬会为你处理。foo.bars最初总是一个空数组。

我认为其他辅助方法中的隐式保存是一个糟糕的设计选择。您的 API 受众知道他们正在制作数据库记录,并且他们理解 的概念save(),这很简单。与 mongoose 的其余部分保持一致,将模型实例上的操作保留在内存中,直到save()调用显式。

但绝对如果您最终在您编写的方法中执行任何 I/O,您必须遵守接受回调函数并error, results在完成时调用它的节点约定。否则,您将应用程序设置为脆性和竞争条件以及各种肮脏的方式。

于 2013-11-03T13:08:36.370 回答
1

如果添加“foo”和保存是一种常见的使用模式(并且它是处理 的最后一个操作,BarModel因此不会不必要地完成多个saves操作),我希望它被适当地命名,以便很明显它有一个明显的副作用,如addFooAndSave。但为了与 Node.JS 约定保持一致,我还将添加您提到的回调(您可以将其传递给save):

BarModel.methods.addFooAndSave = function(foo, callback) {
  // foo.bars = foo.bars || []; // not needed, auto initialized to empty
  foo.bars.push(this.id);

  // Here's the line I'm wondering about... Should I include the line below?
  foo.save(callback);
}

这样你就可以调用:

bar.addFooAndSave(function(err, bar, numAffected) { 
    // response
});

否则,如果保存不那么常见,我会将其作为一个显式步骤并将“foo”添加为您所拥有的方法,然后显式调用save模型实例。

于 2013-11-03T13:17:26.120 回答