2013-10-30 4 views
8

私は内部に格納されたデータを公開するnodejs RESTサービスでMongoDBを使用しています。 $ refを使用するデータを調べる方法について質問があります。ここ

が葯コレクション内の別のオブジェクト(詳細)を参照含むオブジェクトのサンプルである:のNode.jsとMongoDBのモジュールを使用して、実際

{ 
    "_id" : ObjectId("5962c7b53b6a02100a000085"), 
    "Title" : "test", 
    "detail" : { 
     "$ref" : "ObjDetail", 
     "$id" : ObjectId("5270c7b11f6a02100a000001") 
    }, 
    "foo" : bar 
} 

を、私は、次のか:

db.collection("Obj").findOne({"_id" : new ObjectID("5962c7b53b6a02100a000085"}, 
function(err, item) { 
    db.collection(item.$ref).findOne({"_id" : item.$id}, function(err,subItem){ 
     ... 
    }); 
}); 

実際には2つのクエリを作成し、2つのオブジェクトを取得します。これは一種の「遅延読み込み」です(正確ではありませんが)。

私の質問は単純です:1つのクエリでオブジェクトグラフ全体を取り出すことは可能ですか?

ありがとうございます

答えて

4

いいえ、できません。

DBRefを解決するには、参照されたドキュメントを返すためにアプリケーションで追加のクエリを実行する必要があります。多くのドライバーは、自動的にDBRefの照会を形成するヘルパー・メソッドを持っています。ドライバは自動的にDBRefをドキュメントに解決しません。

MongoDB docs http://docs.mongodb.org/manual/reference/database-references/より。

+1

に廃止さにそして私の知る限りでは、ノードMongoDBのネイティブドライバはこれらを解決する方法がありません

db.dereference:私たちは、次のメソッドを削除しましたあなたのためのrefs。 – Brett

4

単一のMongoDBクエリを使用して親オブジェクトを$ refと一緒にフェッチすることはできますか?

いいえ、不可能です。 Mongoはリファレンスのための内部サポートを持っていません。したがって、あなたのアプリケーションにそれらを移入することができます(Brett's answer参照)。

しかし、node.jsコマンドを使ってすべてのrefを持つ親オブジェクトをフェッチすることは可能ですか?

はい、可能です。Mongooseとすることができます。ビルドイン(build-in)の人口サポートがあります。データモデルを少し変更して機能させる必要がありますが、それはあなたが探しているものです。もちろん、そうするために、Mongooseはあなたが行った同じ2つのMongoDBクエリを行います。

1

MongoDb用のドライバはほとんどありません。DBRefの特別なサポートが含まれています。 2つの理由があります:

  1. MongoDbには、参照ドキュメントの取得を可能にする特別なコマンドはありません。したがって、サポートを追加するドライバは、人為的に生成されたオブジェクトを埋め込みます。
  2. APIの「ベアメタル」ほど、それほど意味がありません。実際には、。 MongoDbコレクションはスキーマレスであり、NodeJsドライバがすべての参照が実現されたプライマリドキュメントを戻した場合、コードが参照を破棄せずにドキュメントを保存した場合、サブドキュメントが埋め込まれます。もちろん、それは混乱するでしょう。

フィールド値が異なる場合を除き、私はDBRefタイプを気にせず、代わりにObjectIdを直接格納します。お分かりのように、DBRefは、より豊富なオブジェクトがそのタイプ情報とともに格納されなければならないため、各参照に多数の重複ディスクスペースが必要な場合を除いて、実際には何のメリットもありません。いずれにしても、参照されているコレクションのドキュメントを含む文字列を格納するための不要なオーバーヘッドを考慮する必要があります。

多くの開発者とMongoDb、Inc.は、既存のベースドライバの上にオブジェクトドキュメントマッピングレイヤーを追加しました。 MongoDbとNodejsの一般的なオプションの1つはMongooseです。 MongoDbサーバーは参照された文書を実際に意識していないので、参照の責任はクライアントに移ります。特定のドキュメントから特定のコレクションを一貫して参照することがより一般的であるため、Mongooseは参照をスキーマとして定義することができます。 Mongooseはスキーマレスではありません。

あなたがスキーを持っていることを受け入れることを受け入れると便利な場合、Mongooseは見て分かります。一連の文書から(単一のコレクションから)一連の関連文書を効率的に取り出すことができます。常にネイティブドライバを使用していますが、一般的に操作は非常に効率的であり、より複雑なアプリケーションアーキテクチャからは慎重になるものがあります。

populateの方法(here)をご覧になることを強くお勧めします。

Demo  /* Demo would be a Mongoose Model that you've defined */ 
.findById(theObjectId) 
.populate('detail') 
.exec(function (err, doc) { 
    if (err) return handleError(err); 
    // do something with the single doc that was returned 
}) 

ではなく、常に単一のドキュメントを返す findById、の場合は、 findは、 populateで、使用されたすべての文書は detailsプロパティが自動的に表示されます返されました。それは同じ参照された文書を何度も要求することも賢明です。

Mongooseを使用しない場合は、できるだけクライアント側の参照結合を行わず、できるだけ多くのバッチ処理を行うために$inクエリ演算子を使用することをお勧めします。

+0

ありがとう、私はマングースを見てみましょう。 –

1

私は次の例で望ましい結果に到達:

collection.find({}, function (err, cursor) { 
    cursor.toArray(function (err, docs) { 
     var count = docs.length - 1; 
     for (i in docs) { 
      (function (docs, i) { 
       db.dereference(docs[i].ref, function(err, doc) { 
        docs[i].ref = doc; 
        if (i == count) { 
         (function (docs) { 
          console.log(docs); 
         })(docs); 
        } 
       }); 
      })(docs, i) 
     } 
    }); 
}); 

ないITソリューションは、最高の最高ですが、それは私が見つけた最も簡単な解決策であることを確認してください。 db.dereference方法は、MongoDBのNodejs APIから削除されたようウラジミールの

関連する問題