32

さまざまなコレクション (埋め込みドキュメントではない) でドキュメントを関連付けようとしていますが、Mongooose には問題がありますが、ドキュメントに記載されているように、仮想プロパティを使用して関連付けられたドキュメントを遅延読み込みすることで回避しようとしています。マングースのウェブサイト

問題は、仮想のゲッターが引数として関数を取り、仮想プロパティの戻り値を使用することです。これは、仮想がその値を計算するために非同期呼び出しを必要としない場合に最適ですが、他のドキュメントをロードするために非同期呼び出しを行う必要がある場合には機能しません。私が使用しているサンプルコードは次のとおりです。

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
  });

非同期呼び出しが完了する前に関数が戻るため、これは機能しません。フロー制御ライブラリを使用してこれを機能させる方法はありますか、または匿名関数の代わりに getById 呼び出しを getter に渡すように最初の関数を変更できますか?

4

4 に答える 4

21

コールバックを定義できる仮想メソッドを定義できます。

あなたの例を使用して:

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

そして、唯一のコメンテーターはそれらの衒学的なタイプの1つであるように見えますが、ドキュメントの埋め込みを恐れてはなりません。私が理解していることから、それはモンゴの長所の1つです。

上記のコードを次のように使用します。

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

これは特定の質問ではなく、より広範な問題に対処していますが、それでも提出する価値があると思いました。

Mongoose の query populate関数を使用すると、関連付けられたドキュメントを別のコレクションから簡単に読み込むことができます (仮想を定義するのとほぼ同じ結果になります) 。上記の例を使用すると、Transactionスキーマで ObjectID の ref を指定して (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;
          }
        }
      }
      ...
    });

これは非常に非効率的でハッキリしているように見えますが、これを達成する別の方法を見つけることができませんでした. 最後に、私は node.js、mongoose、および stackoverflow を初めて使用するので、この議論を拡張するのに最適な場所でない場合はご容赦ください。Josh の解決策が私の最終的な「解決策」に最も役立ったというだけです。

于 2011-06-13T20:56:33.727 に答える
3

これは古い質問なので、更新を使用する可能性があると考えました。

非同期仮想フィールドを実現するには、mongoose の github issue: https://github.com/Automattic/mongoose/issues/1894に記載されているように、 mongoose-fillを使用できます。

于 2016-08-23T21:14:07.570 に答える