2013-02-19 24 views
9

スポーツ - >バスケットボール - >男性,スポーツ - >テニス - >女性)のカテゴリをネストし、MySQLではなくMongoを使用しています。Mongoにネストされたカテゴリ(または階層データ)を格納する最も効率的な方法は?

ネストされたカテゴリをMySQLのようなSQLデータベースに格納する方法はわかっていますが、Mongoの対処方法については助言をいただきたいと思います。我々が最適化する必要がある操作は、あるカテゴリまたはサブカテゴリ内のすべての製品を素早く見つけることです。ルートカテゴリの下にいくつかのレイヤーを入れ子にすることができます(メンズバスケットボールカテゴリのすべての製品またはWomen's Tennisカテゴリ)。

This Mongo docは1つのアプローチを示唆していますが、(カテゴリは複数のレベルに達することができるので)必要なサブツリーに操作が必要なときはうまく機能しません。

任意の深度のネストされたカテゴリを効率的に保存および検索するための最良の方法についてのご意見はありますか?

+1

パスはMongoDBのドキュメントリンクは5つのアプローチではなく、1を示していますし、私は三番目は、あなたのユースケースのために完璧に十分なようだと思う – Sammaye

+1

を更新する時に遅いしばらく照会で強いマテリアライズド。 –

答えて

10

最初に決定するのは、使用するツリーの種類です。

あなたのデータとアクセスパターンを考慮する大きな点があります。既にすべての作業の90%が照会されており、それの音(電子商取引)による更新は管理者によってのみ実行されることはほとんどありません。

スポーツからバスケットボール - >メンズ、スポーツ - >テニス - >ウィメンズのように、子どものパスをすばやく照会できるスキーマが必要です。本当に拡張する必要はありません更新する。

MongoDBはこのための良いドキュメントページを持っています:http://docs.mongodb.org/manual/tutorial/model-tree-structures/ 10genは実際には木のための異なるモデルとスキーマメソッドを記述し、それらの主要な浮動小数点数を記述します。

あなたは簡単に照会するために探している場合は、目をキャッチする必要があります1マテリアライズド・パスされています。これは、例えば上で照会するので、木を構築するために非常に興味深い方法であるhttp://docs.mongodb.org/manual/tutorial/model-tree-structures/#model-tree-structures-with-materialized-paths

あなたは「レディース」に上記ましたあなたのツリーの特定のパスの下にリストされているすべての製品を見つけるために

db.products.find({category: /^Sports,Tennis,Womens[,]/}) 

:そうのように:「テニス」で、あなたは、単に(http://docs.mongodb.org/manual/reference/operator/regex/インデックスを使用することができます)事前に固定正規表現を行うことができます。

残念ながら、カテゴリを移動したり名前を変更したりすると、すべての製品を更新する必要があり、1つのカテゴリに数千の製品が存在する可能性があります。

より良い方法は、製品にcat_idを収容して、スキーマを使用して別のコレクションにカテゴリを分離するために、次のようになります。

{ 
    _id: ObjectId(), 
    name: 'Women\'s', 
    path: 'Sports,Tennis,Womens', 
    normed_name: 'all_special_chars_and_spaces_and_case_senstive_letters_taken_out_like_this' 
} 

だから今、あなたのクエリが唯一の彼らは非常に作るべきカテゴリのコレクションを伴いますより小さく、より多くの演奏。ただし、カテゴリを削除すると、製品に触れる必要があります。

だから、「Badmin」に「テニス」を変更する例:あなたは少しあるクライアント側を、それらを引き出す必要がありますので、

db.categories.update({path:/^Sports,Tennis[,]/}).forEach(function(doc){ 
    doc.path = doc.path.replace(/,Tennis/, ",Badmin"); 
    db.categories.save(doc); 
}); 

あいにくのMongoDBは、現時点では何で、クエリ文書の反射を提供していませんしかし、うまくいけば、あまりにも多くのカテゴリが戻ってくる必要はありません。

これは基本的には本当に動作します。更新するのはちょっと難しいですが、インデックスを使ってどのパスでも即座に問い合わせることのできる能力は、私が信じるシナリオにはもっと適しています。

もちろん、このスキーマはネストされたセットモデルと互換性があります:http://en.wikipedia.org/wiki/Nested_set_model私は時間と時間をもう一度見つけましたが、例えば、テニスは「スポーツ」と"余暇"とあなたは、ユーザーがどこから来たかに応じて複数のパスが必要です。

マテリアライズドパスのスキーマだけで簡単に、単純な別のpathを、追加することによって、これをサポートしています。

それは意味がある、かなり長いものがあることを望みます。すべてのカテゴリが異なっている場合

+0

ありがとう!カテゴリのメタ情報(名前やIDなど)を保存する必要がある場合はどうすればよいですか?カテゴリ別に別のコレクションを用意する必要がありますが、商品のカテゴリパスでIDを使用しますか?カテゴリ情報は非常に頻繁に、一年に一度変わるとは考えていません。 – Crashalot

+0

@ Crashalot何かカテゴリに割り当てられているのであれば、それは通常カテゴリに保存するのが最善ですが、代替案はすべての製品に保存することです。頻繁に変更されることはありませんが、製品からだけでなく、そのメタデータを取得する – Sammaye

+0

クール、確認のおかげで。これはまた、カテゴリ名の代わりにパスにカテゴリIDを格納することを示唆しています。これに間違っていると見えるものはありますか?また、Mongoに階層データを格納して照会した経験はありますか?あなたが小さなコンサルティングプロジェクトに興味があるかどうか不思議です。 :) – Crashalot

4

その後、タグと考えます。項目を照会するときにそれらを必要としないので、階層内の項目をエンコードする必要はありません。階層はプレゼンテーション的なものです。各アイテムにそのアイテムのパスにあるすべてのカテゴリをタグ付けします。「スポーツ>野球>シューズ」は{..., categories: ["sport", "baseball", "shoes"], ...}として保存できます。 「スポーツ」カテゴリのすべてのアイテムを検索する場合は{categories: "sport"}、靴だけの場合は{tags: "shoes"}を検索してください。

はこの階層をキャプチャしませんが、あなたが考えてみればそれは問題ではありません。カテゴリが異なる場合は、アイテムを照会するときに階層が役立たない。他の "野球"はありませんので、あなたがそれを検索するときには、階層内の "野球"レベルの下にしか物を取得しません。

私の提案は、カテゴリが明確なものに依存している、と私は彼らがあなたの現在のモデルにはないと思います。しかし、それらを区別できない理由はありません。おそらく、ページに表示する文字列をデータベースのカテゴリ名として使用することを選択しました。代わりに、 "スポーツ"や "womens_shoes"のようなシンボリック名を使用し、ルックアップテーブルを使用してページに表示する文字列を見つけた場合(カテゴリの名前が変更された場合は時間を節約できます。あなたがそれを行う必要があるならば、サイトをより簡単に翻訳することができます)、ページ上に表示されているものとは何の関係もないので、それらが明確であることを容易に確認できます。したがって、階層内に2つの「靴」がある場合(「テニス>女性>靴」および「テニス>メンズ>靴」など)、それらを区別できるように修飾子を追加できます(たとえば、 "womens_shoes"および "mens_shoes" 、または "tennis_womens_shoes")記号名は任意であり、何でもかまいません。数字を使用しても、カテゴリを追加するたびに次の番号を順番に使用することもできます。

+0

あなたの答えの最後の部分は、そのような修飾子を使用して、それが認識された深さと形成に真の標準化を持っていない点を除き、実現経路に似ています。 – Sammaye

+1

これは間違いなくパスが具体化されているわけではありません。シンボリック名には完全な階層を含めるべきではありません。私の例は、ラベルが非常に一般的であったため、階層の一部しか含んでいません。彼らはできるだけ具体的でなければならないが、それ以上ではない。データベース内のアイテムに階層構造をエンコードすることは反パターンであると私は信じています。階層はプレゼンテーションの細部であり、マテリアライズドパスを使用すると、各項目の階層が不必要に繰り返され、データモデルが脆くなり、後で階層を変更することを不必要に困難にします。 – Theo

関連する問題