マングースサブドキュメントとネストされたスキーマ


122

サブドキュメントを使用することと、メインスキーマのより深い層を使用することの長所と短所に興味があります。

var subDoc = new Schema({
  name: String
});

var mainDoc = new Schema({
  names: [subDoc]
});

または

var mainDoc = new Schema({
  names: [{
    name: String
 }]
});

私は現在、あらゆる場所でサブドキュメントを使用していますが、主にパフォーマンスやクエリの問題について知りたいと思っています。


答えを入力しようとしましたが、方法がわかりませんでした。しかし、ここで一見を与える:mongoosejs.com/docs/subdocs.html
gustavohenke

ここでは、データベースのスキーマを作成するときに自問するMongoDBの考慮事項についての良い応答は次のとおりです。stackoverflow.com/questions/5373198/...
anthonylawsonは

_idフィールドも説明する必要があるということですか?つまり、有効になっている場合、それは少し自動ではありませんか?
Vadorequest、2014

_idサブドキュメントの分野がユニークであるかどうか誰でも知っていますか?(OPの質問の2番目の方法を使用して作成)
埼玉

回答:


72

docsによると、それはまったく同じです。ただし、スキーマを使用すると_idフィールドも追加され(無効にしていない限り)、サブドキュメントの追跡にさらに多くのリソースが使用されると考えられます。

代替宣言構文

v3の新機能サブドキュメントスキーマインスタンスにアクセスする必要がない場合は、オブジェクトリテラル[...]を渡すだけでサブドキュメントを宣言することもできます。


1
しかし、私はこれを試しました。サブドキュメントのデータが別のコレクションに保存されない理由。常にmainDocコレクション内に格納されます。
Fizer Khan、2013

17
これがサブドキュメントの仕組みです。それらはドキュメントの中に埋め込まれています。mongooseで遊ぶ前に、基礎となるMongoDBを理解してください。
AndyL 2013年

1
_idを追加するスキーマに関しては、それは理にかなっていますが、サブドキュメントの配列とオブジェクトリテラルの配列を使用してスキーマを作成し、_idを両方に追加しました。行動は変化しましたか?
Drew Goodwin

:@DrewGoodwinは、それはしばらくの間、このようにされているように思えるstackoverflow.com/questions/17254008/...
cheesemacfly

37

モデルのさまざまな部分で再利用されるスキーマがある場合は、子ドキュメントに個別のスキーマを定義して、自分で複製する必要がないようにすると便利です。


4
これは素晴らしい答えです。時々、複数のモデルでサブドキュメントを使用したり、区別する必要があるモデルに2つのフィールドがありますが、サブドキュメント構造は同じです。
MartinHallén14年

2
また、冗長な情報を保存することのメリットとデメリットも考慮する必要があります。
Sam Vloeberghs 2014年

25

静的ドキュメントである場合、またはパフォーマンスへの影響のために数百以下の場合は、埋め込みドキュメントを使用する必要があります。私はその問題についてしばらく前に経験しました。新しく、MongoDBのソリューションアーキテクトとして働いているAsya Kamskyが、「サブドキュメントの使用」についての記事を書きました。

私はそれが解決策やベストプラクティスを探している人に役立つことを願っています。

http://askasya.com/post/largeembeddedarraysの元の投稿。https://stackoverflow.com/users/431012/asya-kamskyで彼女のstackoverflowプロファイルにアクセスできます。

まず、なぜそのようなことをしたいのかを考えなければなりません。通常、私は、このドキュメントを取得するときに、いつでも取得したいものを埋め込むことをお勧めします。これの裏側は、ドキュメントに戻したくないものをドキュメントに埋め込みたくないということです。

私が実行するアクティビティをドキュメントに埋め込むと、最初はうまくいきます。私のアクティビティはすべてそこにあり、1回の読み取りで、表示したいすべての情報を取得できます。最後の2つのコメントはありますか?」ですが、6か月が経過した後はどうなりますか。私がずっと前にやったことは気にせず、特に古いアクティビティを探しに行かない限り、それらを私に見せたくないですか?

最初に、どんどんどんどん大きくなるドキュメントを返して、ドキュメントのますます小さな部分を気にすることになります。しかし、プロジェクションを使用して一部の配列のみを返すことができます。実際の痛みは、ディスク上のドキュメントが大きくなり、エンドユーザーに一部だけを返す場合でも、すべて読み取られることですが、私が活動している限り活動は止まらないので、ドキュメントはどんどん成長し続けます。

これに関する最も明白な問題は、最終的には16MBのドキュメント制限に達することですが、それはあなたが心配するべきことではありません。継続的に増大するドキュメントは、ディスクに再配置する必要があるたびに、ますます高いコストが発生します。また、断片化の影響を軽減するための対策を講じたとしても、書き込みは全体的に不必要に長くなり、アプリケーション全体の全体的なパフォーマンスに影響します。

アプリケーションのパフォーマンスを完全に停止させることができるもう1つのことは、この増え続ける配列にインデックスを付けることです。つまり、この配列を持つドキュメントが再配置されるたびに、更新が必要なインデックスエントリの数は、そのドキュメント内のインデックス付きの値の数に正比例し、配列が大きくなるほど、その数は大きくなります。あります。

配列がデータモデルに適している場合に配列を使用することでこれを怖がらせたくありません。これらはドキュメントデータベースデータモデルの強力な機能ですが、すべての強力なツールと同様に、適切な状況で使用する必要があります注意して使用する必要があります。


3
これが一番の答えです。それはお金に強打です。MongoDB独自のホワイトペーパーでも、ほぼ同じことが述べられています。
ジェイエドワーズ

バケットパターンに関するこの記事は、Asyaが上手に話していることを補完しています。 mongodb.com/blog/post/building-with-patterns-the-bucket-pattern OPの質問のsubDocスキーマは、バケットパターンでうまく機能すると思います。
plong0

13

基本的に、変数nestedDovを作成してここに配置しますname: [nestedDov]

シンプルバージョン:

var nestedDoc = new Schema({
  name: String
});

var mainDoc = new Schema({
  names: [nestedDoc]
});

JSONの例

{
    "_id" : ObjectId("57c88bf5818e70007dc72e85"),
    "name" : "Corinthia Hotel Budapest",
    "stars" : 5,
    "description" : "The 5-star Corinthia Hotel Budapest on the Grand Boulevard offers free access to its Royal Spa",
    "photos" : [
        "/photos/hotel/corinthiahotelbudapest/1.jpg",
        "/photos/hotel/corinthiahotelbudapest/2.jpg"
    ],
    "currency" : "HUF",
    "rooms" : [
        {
            "type" : "Superior Double or Twin Room",
            "number" : 20,
            "description" : "These are some great rooms",
            "photos" : [
                "/photos/room/corinthiahotelbudapest/2.jpg",
                "/photos/room/corinthiahotelbudapest/5.jpg"
            ],
            "price" : 73000
        },
        {
            "type" : "Deluxe Double Room",
            "number" : 50,
            "description" : "These are amazing rooms",
            "photos" : [
                "/photos/room/corinthiahotelbudapest/4.jpg",
                "/photos/room/corinthiahotelbudapest/6.jpg"
            ],
            "price" : 92000
        },
        {
            "type" : "Executive Double Room",
            "number" : 25,
            "description" : "These are amazing rooms",
            "photos" : [
                "/photos/room/corinthiahotelbudapest/4.jpg",
                "/photos/room/corinthiahotelbudapest/6.jpg"
            ],
            "price" : 112000
        }
    ],
    "reviews" : [
        {
            "name" : "Tamas",
            "id" : "/user/tamas.json",
            "review" : "Great hotel",
            "rating" : 4
        }
    ],
    "services" : [
        "Room service",
        "Airport shuttle (surcharge)",
        "24-hour front desk",
        "Currency exchange",
        "Tour desk"
    ]
}

例:

ここに画像の説明を入力してください


1
これは、パフォーマンスの1つである問題にはまったく対応していません。
cyberwombat 2016

私はより意味をなすために少し編集しました。どう思いますか?
Wayne Chiu

3
問題は、ネストされたスキーマをどのように実行するかということではありません。ネストされたスキーマまたは埋め込まれたサブドキュメントでMongooseのパフォーマンスが向上するかどうかについての議論。基本的には、Mongooseがどちらか一方を好むベンチマーク、ソート、またはエッジケースについて話しています。そして、選択した回答が言及しているように、少なくともV3以降は、何の違いもないようです。
cyberwombat 2016

17
多分OPで動作しないかもしれませんが、これは非常に役に立ちました。ありがとう。
ジーンヒギンズ

これは、3つのスキーマすべてが1つの.jsファイルで宣言されている場合に適しています。3つの異なる.jsファイルで宣言されている場合、どのように処理できますか?
Satyam

9

これは、SOの複数の投稿によって別の場所で処理されると思います。

少しだけ:

大きな鍵は、ここでは単一の答えはなく、かなり複雑なトレードオフのセットのみであることです。


3
多分私は私の質問を正しく表現していません-これはデータベースをどのように構造化するべきかという問題ではなく、サブスキーマを使用するか、より深い層に配列を書き込むだけの問題です。サブスキーマを使用する主な原因は、カスタムスキーマタイプを使用してそれらを検証できることです。これは、ネストされた配列では機能しないものです(前に私がSOで質問したもの)。サブドキュメントがネストされた配列とほとんど同じであると私が知ることができる限り-私はそれの内部を知らない-それらを使用するとパフォーマンスの問題などが発生するかどうか。
cyberwombat 2013年

0

2つの間にいくつかの違いがあります。

  • ネストされたスキーマを使用すると、検証に役立ちます。

  • ネストされたスキーマは、他のスキーマで再利用できます。

  • ネストされたスキーマは、「_ id:false」を使用しない限り、「_ id」フィールドをサブドキュメントに追加します
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.