32

我正在尝试将不同集合中的文档(不是嵌入式文档)关联起来,虽然在 Mongooose 中存在问题,但我现在正试图通过延迟加载具有虚拟属性的关联文档来解决它,如记录在猫鼬网站

问题是虚拟的 getter 将函数作为参数并使用虚拟属性的返回值。当虚拟不需要任何异步调用来计算它的值时,这很好,但是当我需要进行异步调用来加载其他文档时不起作用。这是我正在使用的示例代码:

TransactionSchema.virtual('notebook')
  .get( function() { // <-- the return value of this function is used as the property value
    Notebook.findById(this.notebookId, function(err, notebook) {
      return notebook; // I can't use this value, since the outer function returns before we get to this code
    })
    // undefined is returned here as the properties value
  });

这不起作用,因为函数在异步调用完成之前返回。有没有办法可以使用流控制库来完成这项工作,或者我可以修改第一个函数,以便将 findById 调用传递给 getter 而不是匿名函数?

4

4 回答 4

21

您可以定义一个虚拟方法,您可以为其定义一个回调。

使用您的示例:

TransactionSchema.method('getNotebook', function(cb) {
  Notebook.findById(this.notebookId, function(err, notebook) {
    cb(notebook);
  })
});

虽然唯一的评论者似乎是那些迂腐的类型之一,但您也不应该害怕嵌入文档。据我了解,它是 mongos 的强项之一。

像这样使用上面的代码:

instance.getNotebook(function(nootebook){
    // hey man, I have my notebook and stuff
});
于 2011-05-20T22:52:32.767 回答
6

虽然这解决了更广泛的问题而不是具体问题,但我仍然认为值得提交:

通过使用 Mongoose 的查询填充功能,您可以轻松地从另一个集合中加载关联的文档(与定义虚拟的结果几乎相同) 。使用上面的示例,这需要在架构中指定 ObjectID 的 ref Transaction(指向 Notebook 集合),然后populate(NotebookId)在构造查询时调用。链接的 Mongoose 文档非常彻底地解决了这个问题。

我不熟悉猫鼬的历史,但我猜populate在提交这些早期答案时并不存在。

于 2012-11-18T23:02:53.250 回答
3

Josh 的方法非常适合单个文档查找,但我的情况稍微复杂一些。我需要查找整个对象数组的嵌套属性。例如,我的模型看起来更像这样:

var TransactionSchema = new Schema({
  ...
  , notebooks: {type: [Notebook]}
});

var NotebookSchema = new Schema({
  ...
  , authorName: String  // this should not necessarily persist to db because it may get stale
  , authorId: String
});

var AuthorSchema = new Schema({
  firstName: String
  , lastName: String
});

然后,在我的应用程序代码中(我正在使用 Express),当我得到一个事务时,我想要所有带有作者姓氏的笔记本:

...
TransactionSchema.findById(someTransactionId, function(err, trans) {
  ...
  if (trans) {
    var authorIds = trans.notebooks.map(function(tx) {
        return notebook.authorId;
      });

    Author.find({_id: {$in: authorIds}, [], function(err2, authors) {
      for (var a in authors) {
        for (var n in trans.notebooks {
          if (authors[a].id == trans.notebooks[n].authorId) {
            trans.notebooks[n].authorLastName = authors[a].lastName;
            break;
          }
        }
      }
      ...
    });

这似乎非常低效和hacky,但我想不出另一种方法来实现这一点。最后,我是 node.js、mongoose 和 stackoverflow 的新手,如果这不是扩展这个讨论的最合适的地方,请原谅我。只是 Josh 的解决方案对我最终的“解决方案”最有帮助。

于 2011-06-13T20:56:33.727 回答
3

由于这是一个老问题,我认为它可能会使用更新。

要实现异步虚拟字段,可以使用mongoose-fill,如 mongoose 的 github issue 中所述:https ://github.com/Automattic/mongoose/issues/1894

于 2016-08-23T21:14:07.570 回答