2

Mongodb への埋め込みを理解しようとしましたが、十分なドキュメントが見つかりませんでした。書き込みはドキュメント間でアトミックではなく、2 つのルックアップがあるため、リンクはお勧めしません。誰かがこれを解決する方法を知っていますか、それともneo4jのようなグラフDBに行くように勧めてくれませんか?

多対多の関係を必要とするアプリケーションを構築しようとしています。説明するために、ライブラリの例を取り上げます。ユーザーの友人が読んでいる本や、同じような考えを持つ隣人が読んでいる本に基づいて、ユーザーに本を提案することができます。

ユーザーとブックがあります。ユーザーは本を借りており、他のユーザーである友達がいます

  1. ユーザーが与えられた場合、彼が読んでいるすべての本と、その本のための共通の友達の数が必要です
  2. 与えられた本には、それを読んでいるすべての人が必要です。ユーザー A が与えられた場合、これは、本を読んでいる人々とユーザー A の友人の共通部分を返します。これは相互の友情です。

ユーザー = [

       { name: 'xyz', 'id':'000000', friend_ids:['949583','958694']}

       { name: 'abc', 'id':'000001', friend_ids:['949582','111111']}

      ]

本 = [

      {'book':'da vinci code', 'author': 'dan brown', 'readers'=['949583', '000000']}

      {'book':'iCon', 'author': 'Young', 'readers'=['000000', '000001']}

      ]

上記のように、mongo DB を使用する場合は、双方向のルックアップを行う可能性があるため、一般に 2 つのドキュメントが必要です。ドキュメントを別のドキュメントに複製 (埋め込み) すると、多くの重複が発生する可能性があります (これらのスキーマには、示されているよりもはるかに多くの情報が格納される可能性があります)。

データを正しくモデリングしていますか? これはmongodbで効果的に行うことができますか、それともグラフDBを見るべきですか。

4

2 に答える 2

6

免責事項: 私は Neo4j で働いています

概要、要件、およびデータの種類から、アプリはむしろグラフ データベースのスイートスポットにあるようです。

グラフデータベースで簡単なスパイクを行い、それがどのように進んでいるかを確認することをお勧めします.

  • 重複することはありません
  • アトミック操作のトランザクションがあります
  • リンクをたどるのは自然な操作です
  • ローカル クエリ (ユーザーや本などから) は安価で高速です
  • 最短経路などのグラフ アルゴリズムを使用して、データに関する興味深い情報を見つけることができます
  • レコメンデーションや同様の操作は、グラフ データベースにとって自然なことです。

いくつかの質問:

  • そもそもなぜMongoDBを選んだのですか?
  • どの実装言語を使用していますか?
于 2012-02-15T00:04:23.180 に答える
5

上記の基本的なスキーマの提案は、MongoDB でうまく機能しますが、いくつかの提案があります。

  1. 識別子には、文字列ではなく整数を使用してください。多くの場合、整数は MongoDB によってよりコンパクトに格納されます (整数は常に 8 バイトですが、文字列の格納サイズは文字列の長さに依存します)。findAndModifyを使用して、一意のシーケンス ジェネレーター (一部のリレーショナル データベースの auto_increment など) をエミュレートできます。これがどのように行われるかの例については、Mongoengine の SequenceFieldを参照してください。また、常に 12 バイトのObjectIdを使用することもできますが、データベースに調整情報を保存する必要がなく、一意であることが事実上保証されています。
  2. このフィールドは常に MongoDB に存在し、デフォルトの一意のインデックスが作成されているため、 の_id代わりに フィールドを使用する必要があります。idこれは、_idが常に一意であり、 による検索_idが非常に高速であることを意味します。

この種のスキーマを使用すると複数find()の が必要になり、毎回ネットワーク ラウンドトリップのオーバーヘッドが発生することは間違いありません。ただし、上記で提案したクエリごとに、いくつかの簡単なアプリケーション コードと組み合わせて、2 つ以上のルックアップが必要になることはありません。

  1. 「与えられたユーザーについて、彼が読んでいるすべての本と、その本に共通の友達の数が必要です」

    a. 問題のユーザーを調べてから、
    b. を使用して書籍コレクションをクエリしdb.books.find({_id: {$in: [list, of, books, for, the, user]}})、次に
    c. 本ごとに、その本の読者とユーザーの友達の和集合を計算します
  2. 「本があれば、それを読んでいるすべての人が必要です。」

    を。問題の本を調べてから、
    b. $in再びlikeを使用して、その本を読んでいるすべてのユーザーを検索します。db.users.find({_id: {$in: [list, of, users, reading, book]}})
  3. 「ユーザーAが与えられた場合、これは本を読んでいる人々とユーザーAの友人の交差点を返します。」

    を。問題のユーザーを調べてから、
    b. 問題の本を調べてから、
    c. ユーザーの友達と本の読者の和集合を計算する

$inリストが非常に長い場合は、N 個の項目のリストに対して N 回のルックアップを実行するのと実質的に同等であるため、遅くなる可能性があることに注意してください。ただし、サーバーがこれを行うため、必要なネットワーク ラウンドトリップは N 回ではなく 1 回だけです。

これらのクエリの一部を使用する代わりに$in、配列フィールドにインデックスを作成し、配列内の特定の値を持つドキュメントのコレクションをクエリできます。たとえば、上記のクエリ #1 の場合、次のようにすることができます。

// create an index on the array field "readers"
db.books.ensureIndex({readers: 1})

// now find all books for user whose id is 1234
db.books.find({readers: 1234})

これはマルチキー インデックス$inと呼ばれ、場合によってはパフォーマンスが向上します。実際のエクスペリエンスは、ドキュメントの数とリストのサイズによって異なります。

于 2012-02-15T21:07:38.647 に答える