web-dev-qa-db-ja.com

CouchDBドキュメントのモデリングの原則

私は今しばらく答えようとしていた質問がありますが、理解できません:

CouchDBドキュメントをどのように設計または分割しますか?

たとえば、ブログ投稿をご覧ください。

半「リレーショナル」な方法は、いくつかのオブジェクトを作成することです。

  • 役職
  • ユーザー
  • コメント
  • 鬼ごっこ
  • スニペット

これは非常に理にかなっています。しかし、同じことをモデル化するためにcouchdbを使用しようとしています(すべての理由から)、それは非常に困難です。

そこにあるブログの投稿のほとんどは、これを行う方法の簡単な例を示しています。基本的には同じように分割されますが、「任意の」プロパティを各ドキュメントに追加できると言います。これは間違いなくニースです。 CouchDBには次のようなものがあります。

  • 投稿(ドキュメント内のタグとスニペット「擬似」モデルを使用)
  • コメント
  • ユーザー

コメントとユーザーをそこに入れることができると言う人もいるので、次のようにします。

post {
    id: 123412804910820
    title: "My Post"
    body: "Lots of Content"
    html: "<p>Lots of Content</p>"
    author: {
        name: "Lance"
        age: "23"
    }
    tags: ["sample", "post"]
    comments {
        comment {
            id: 93930414809
            body: "Interesting Post"
        } 
        comment {
            id: 19018301989
            body: "I agree"
        }
    }
} 
</ code>

それはとても素敵に見え、理解しやすいです。また、すべての投稿文書からコメントだけを抽出するビューを作成して、ユーザーやタグと同じようにコメントモデルに入れる方法を理解しています。

しかし、その後、「なぜサイト全体を1つのドキュメントにまとめるだけではないのか」と考えています。

site {
    domain: "www.blog.com"
    owner: "me"
    pages {
        page {
            title: "Blog"
            posts {
                post {
                    id: 123412804910820
                    title: "My Post"
                    body: "Lots of Content"
                    html: "<p>Lots of Content</p>"
                    author: {
                        name: "Lance"
                        age: "23"
                    }
                    tags: ["sample", "post"]
                    comments {
                        comment {
                            id: 93930414809
                            body: "Interesting Post"
                        } 
                        comment {
                            id: 19018301989
                            body: "I agree"
                        }
                    }
                }
                post {
                    id: 18091890192984
                    title: "Second Post"
                    ...
                }
            }
        }
    }
} 
</ code>

簡単にビューを作成して、必要なものを見つけることができます。

それから私が持っている質問は、ドキュメントをいつより小さなドキュメントに分割するか、またはドキュメント間で「関係」を作成するタイミングをどのように決定するかです。

私はそれがはるかに「オブジェクト指向」であり、次のように分割されている場合、値オブジェクトにマッピングするのが簡単になると思います:

posts {
    post {
        id: 123412804910820
        title: "My Post"
        body: "Lots of Content"
        html: "<p>Lots of Content</p>"
        author_id: "Lance1231"
        tags: ["sample", "post"]
    }
}
authors {
    author {
        id: "Lance1231"
        name: "Lance"
        age: "23"
    }
}
comments {
    comment {
        id: "comment1"
        body: "Interesting Post"
        post_id: 123412804910820
    } 
    comment {
        id: "comment2"
        body: "I agree"
        post_id: 123412804910820
    }
} 
</ code>

...しかし、それはリレーショナルデータベースのように見え始めます。また、「ドキュメント内のサイト全体」のようなものを継承することが多いため、リレーションでモデル化することはより困難です。

リレーショナルデータベースとドキュメントデータベースをどのように/いつ使用するかについて多くのことを読みましたので、ここでは主な問題ではありません。 CouchDBでデータをモデル化するときに適用するのに適したルール/原則は何ですか?.

別の例は、XMLファイル/データを使用する場合です。一部のXMLデータには10レベル以上のネストがあり、ActiveRecord、CouchRestからJSONをレンダリングするのと同じクライアント(Ajax on Rails、またはFlex)を使用して視覚化したいと思います、またはその他のオブジェクトリレーショナルマッパー。次のようなサイト構造全体である巨大なXMLファイルを取得する場合があります。これをValueオブジェクトにマッピングして、Rails = appなので、データをシリアル化/逆シリアル化する別の方法を書く必要はありません:

<pages>
    <page>
        <subPages>
            <subPage>
                <images>
                    <image>
                        <url/>
                    </image>
                </images>
            </subPage>
        </subPages>
    </page>
</pages> 
</ code>

したがって、一般的なCouchDBの質問は次のとおりです。

  1. 文書(関係など)を分割するために、どのルール/原則を使用していますか?
  2. サイト全体を1つのドキュメントにまとめることはできますか?
  3. もしそうなら、任意の深さレベルのドキュメントのシリアライズ/デシリアライズをどのように処理しますか(上記の大きなjsonの例やxmlの例のように)?
  4. または、それらをVOにしないで、「これらはオブジェクトリレーショナルマップにネストされすぎているので、生のXML/JSONメソッドを使用してアクセスするだけ」と決めただけですか。

あなたの助けに感謝します。CouchDBでデータを分割する方法の問題は、「これが今後のやり方です」と言うのは難しいです。私はすぐにそこに着くと思います。

私は次のサイト/プロジェクトを研究しました。

  1. CouchDBの階層データ
  2. CouchDB Wiki
  3. ソファ-CouchDBアプリ
  4. CouchDB The Definitive Guide
  5. PeepCode CouchDB Screencast
  6. CouchRest
  7. CouchDB README

...しかし、彼らはまだこの質問に答えていません。

118
Lance Pollard

私はこれが古い質問であることを知っていますが、私はこのまったく同じ問題に対する最良のアプローチを見つけようとしてそれに出くわしました。 Christopher Lenzが CouchDBで「結合」をモデル化する方法 についての素敵なブログ投稿を書いています。私の持ち帰りの1つは、「関連データの競合しない追加を許可する唯一の方法は、その関連データを個別のドキュメントに入れることです。」そのため、簡単にするために、「非正規化」に傾倒したいと思うでしょう。ただし、特定の状況では書き込みが競合するため、自然な障壁にぶつかることになります。

投稿とコメントの例では、1つの投稿とそのコメントがすべて1つのドキュメントに存在する場合、2人が同時にコメントを投稿しようとすると(つまり、ドキュメントの同じリビジョンに対して)、競合が発生します。これは、「単一ドキュメント内のサイト全体」のシナリオではさらに悪化します。

だから、経験則では「痛むまで非正規化する」と思うが、「痛む」のは、同じリビジョンのドキュメントに対して複数の編集が投稿される可能性が高いところだ。

16
jake l

book は、正しく思い出せば、ドキュメントが更新される頻度を考慮しながら、「痛む」まで非正規化することを意味します。

  1. 文書(関係など)を分割するために、どのルール/原則を使用していますか?

経験則として、問題のアイテムに関するページを表示するために必要なすべてのデータを含めます。つまり、現実世界の紙に印刷して、誰かに渡すすべてのものです。例えば。株価資料には、数字に加えて会社名、取引所、通貨が含まれます。契約文書には、取引相手の名前と住所、日付と署名者に関するすべての情報が含まれます。しかし、個別の日付からの株価は個別の文書を形成し、個別の契約は個別の文書を形成します。

  1. サイト全体を1つのドキュメントにまとめることはできますか?

いいえ、それはばかげているでしょう、なぜなら:

  • 更新ごとにサイト全体(ドキュメント)を読み書きする必要がありますが、これは非常に非効率的です。
  • ビューキャッシングの恩恵は受けません。
15
Eero

Jakeの応答は、CouchDBを扱う上で最も重要な側面の1つであり、スコーピングの決定を下すのに役立つ可能性があると思います。つまり、競合です。

投稿自体の配列プロパティとしてコメントがあり、大量の巨大な「投稿」ドキュメントを含む「投稿」DBがある場合、ジェイクと他の人が正しく指摘したように、シナリオを想像できます2人のユーザーが同時に編集を投稿ドキュメントに送信し、そのドキュメントの衝突とバージョンの競合が発生する、本当に人気のあるブログ投稿。

ASIDE:As この記事が指摘している 、また、そのドキュメントをリクエスト/更新するたびに、ドキュメント全体を取得/設定する必要があることを考慮してください。サイト全体を表す巨大なドキュメントや、多くのコメントを含む投稿の周りは、回避したい問題になる可能性があります。

投稿がコメントとは別にモデル化され、2人がストーリーにコメントを送信する場合、それらは競合の問題なくそのDB内の2つの「コメント」ドキュメントになります。 「コメント」データベースに2つの新しいコメントを追加するための2つのPUT操作。

次に、投稿のコメントを返すビューを作成するには、postIDを渡し、その親投稿IDを参照するすべてのコメントを論理的な順序でソートして出力します。 [コメント]ビューのキーとして[postID、byUsername]のようなものを渡して、親投稿と結果のソート方法またはそれらの行に沿ったものを示すこともできます。

MongoDBはドキュメントを少し異なる方法で処理し、ドキュメントのサブ要素にインデックスを作成できるようにします。そのため、MongoDBメーリングリストで同じ質問が表示され、「コメントを親投稿のプロパティにするだけ」と言う場合があります。

Mongoの書き込みロックとシングルマスターの性質により、2人がコメントを追加するという矛盾するリビジョンの問題はそこに発生せず、前述のように、コンテンツのクエリ機能はサブのためにあまり悪い影響を受けません。インデックス。

そうは言っても、eitherDBのサブ要素が巨大になる(数万のコメントなど)場合は、これらの別々の要素を作るための両方のキャンプ。確かに、ドキュメントとそのサブ要素の大きさに上限があるため、Mongoの場合はそうであることがわかりました。

5
Riyad Kalla