mongoの外部キー?


93

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

MongoDBでこのようなスキームを設計するにはどうすればよいですか?外部キーはないと思います!


9
ドキュメント指向ではなく、関係的に考えています。:P
Pat

6
リレーショナルデータベースが必要なのに、なぜMongoDBを使用しているのですか?
Adam Robinson

47
:D私はドキュメント指向の方法を理解しようとしています。このタスクをどのように解決できますか?
Mark Pegasov

ドキュメント指向の考え方に対する回答が必要な場合は、stackoverflow.com / a / 18637581/80428を参照してください。現在受け入れられている答えは機能しますが、NoSQLの目的ではない、ドキュメントストアへのリレーショナルデータベースを駆使しています。
ジェイウィック2017年

回答:


27

MongoidやMongoMapperのようなORMの使用に興味があるかもしれません。

http://mongoid.org/docs/relations/referenced/1-n.html

MongoDBのようなNoSQLデータベースでは、「テーブル」ではなくコレクションがあります。ドキュメントはコレクション内でグループ化されます。単一のコレクションに、あらゆる種類のデータを含むあらゆる種類のドキュメントを含めることができます。基本的に、NoSQLデータベースでは、データとその関係を編成する方法を決定する必要があります。

MongoidとMongoMapperが行うことは、関係を非常に簡単にセットアップするための便利なメソッドを提供することです。私があなたに与えたリンクをチェックして、どんなことでも聞いてください。

編集:

mongoidでは、次のようにスキーマを記述します。

class Student
  include Mongoid::Document

    field :name
    embeds_many :addresses
    embeds_many :scores    
end

class Address
  include Mongoid::Document

    field :address
    field :city
    field :state
    field :postalCode
    embedded_in :student
end

class Score
  include Mongoid::Document

    belongs_to :course
    field :grade, type: Float
    embedded_in :student
end


class Course
  include Mongoid::Document

  field :name
  has_many :scores  
end

編集:

> db.foo.insert({group:"phones"})
> db.foo.find()                  
{ "_id" : ObjectId("4df6539ae90592692ccc9940"), "group" : "phones" }
{ "_id" : ObjectId("4df6540fe90592692ccc9941"), "group" : "phones" }
>db.foo.find({'_id':ObjectId("4df6539ae90592692ccc9940")}) 
{ "_id" : ObjectId("4df6539ae90592692ccc9940"), "group" : "phones" }

ドキュメント間の関係を作成するために、そのObjectIdを使用できます。


アイテムの入ったドキュメントがあり、都市を縛りたい。都市でコレクションを作成しましたが、都市とアイテムをバインドする方法がわかりません。PSは私の悪い英語をごめんなさい。
マークペガソフ2011年

UPD。PHPをプログラミング言語として使用していますが、Rubyで書かれている場合、mongoidをどのように使用できますか?
Mark Pegasov、2011年

1
@ЖирайрКазаросян:なるほど:) Ruby開発者であると、Rubyでしか考えられない:)私はPHPとMongoの経験がないと思いますが、このリンクを確認できます:mongodb.org/display/DOCS/ …
ネリアン

1
@ЖирайрКазаросян:私は実用的なプログラマーによって、Ruby on Railsを使った本のWeb開発でRuby on Railsを学びました。このスクリーンキャストcodeschool.com/courses/rails-for-zombies
Nerian

2
後の読者のために、「テーブル」はMongoDBの「コレクション」です。行はドキュメント、列はフィールドです...混乱する場合に備えて。
cpu_meltdown

64

mongodbでこのようにテーブルを設計するにはどうすればよいですか?

最初に、いくつかの命名規則を明確にします。MongoDBはのcollections代わりにを使用しますtables

外部キーはないと思います!

次のモデルを考えてみましょう:

student
{ 
  _id: ObjectId(...),
  name: 'Jane',
  courses: [
    { course: 'bio101', mark: 85 },
    { course: 'chem101', mark: 89 }
  ]
}

course
{
  _id: 'bio101',
  name: 'Biology 101',
  description: 'Introduction to biology'
}

明らかにジェーンのコースリストはいくつかの特定のコースを指しています。データベースはシステムに制約(つまり、外部キー制約)を適用しないため、「カスケード削除」または「カスケード更新」はありません。ただし、データベースには正しい情報が含まれています。

さらに、MongoDBには、これらの参照の作成を標準するのに役立つDBRef標準があります。実際、そのリンクを見ると、同様の例があります。

このタスクをどのように解決できますか?

明確にするために、MongoDBはリレーショナルではありません。標準の「通常の形式」はありません。格納するデータと実行するクエリに適したデータベースをモデル化する必要があります。


2
では、学生のコレクションからコース名のデータを取得するにはどうすればよいですか?db.student.find()は次のようなコースを返します:[{コース: 'bio101'、マーク:85}]
Mark Pegasov

@ЖирайрКазаросян:> db.foo.find({'_ id':ObjectId( "4df6539ae90592692ccc9940")})-------------> {"_id":ObjectId( "4df6539ae90592692ccc9940")、 "グループ": "電話"}
Nerian

mongo docからDBREFについて:「DBRefを使用するやむを得ない理由がない限り、代わりに手動参照を使用してください。」
kroiz

22

いわゆるforeign keyMongoDBで定義できます。しかし、我々は、データの整合性を維持する必要が自分で。例えば、

student
{ 
  _id: ObjectId(...),
  name: 'Jane',
  courses: ['bio101', 'bio102']   // <= ids of the courses
}

course
{
  _id: 'bio101',
  name: 'Biology 101',
  description: 'Introduction to biology'
}

coursesフィールドが含まれている_idコースの秒。1対多の関係を定義するのは簡単です。ただし、studentのコース名を取得する場合は、Jane別の操作を実行してをcourse介してドキュメントを取得する必要があります_id

コースbio101が削除された場合、ドキュメントのcoursesフィールドを更新するために別の操作を実行する必要がありstudentます。

詳細:MongoDBスキーマ設計

MongoDBのドキュメントタイプの性質は、関係を定義する柔軟な方法をサポートします。1対多の関係を定義するには:

埋め込みドキュメント

  1. 1対数に適しています。
  2. 利点:別のドキュメントに対して追加のクエリを実行する必要がありません。
  3. 欠点:埋め込まれたドキュメントのエンティティを個別に管理できません。

例:

student
{
  name: 'Kate Monster',
  addresses : [
     { street: '123 Sesame St', city: 'Anytown', cc: 'USA' },
     { street: '123 Avenue Q', city: 'New York', cc: 'USA' }
  ]
}

子供の参照

上記のstudent/のcourse例のように。

親の参照

ログメッセージなど、1〜数十億に適しています。

host
{
    _id : ObjectID('AAAB'),
    name : 'goofy.example.com',
    ipaddr : '127.66.66.66'
}

logmsg
{
    time : ISODate("2014-03-28T09:42:41.382Z"),
    message : 'cpu is on fire!',
    host: ObjectID('AAAB')       // Reference to the Host document
}

事実上、aはのhost親ですlogmsghostログメッセージが数十億である場合、IDを参照すると多くのスペースを節約できます。

参照:

  1. 6 MongoDBスキーマ設計の経験則:パート1
  2. 6 MongoDBスキーマ設計の経験則:パート2
  3. 6 MongoDBスキーマ設計の経験則:パート3
  4. ドキュメント参照を使用した1対多の関係のモデル化

19

リトルMongoDBの書籍

結合を使用するもう1つの方法は、データを非正規化することです。歴史的に、非正規化はパフォーマンスに敏感なコードのために、またはデータを(監査ログのように)スナップショットする必要があるときに予約されていました。ただし、NoSQLの人気が高まり、その多くに結合がないため、通常のモデリングの一部としての非正規化がますます一般的になっています。これは、すべてのドキュメントのすべての情報を複製する必要があるという意味ではありません。ただし、データの重複を恐れて設計上の決定を下すのではなく、どの情報がどのドキュメントに属しているかに基づいてデータをモデル化することを検討してください。

そう、

student
{ 
    _id: ObjectId(...),
    name: 'Jane',
    courses: [
    { 
        name: 'Biology 101', 
        mark: 85, 
        id:bio101 
    },
  ]
}

RESTful APIデータの場合、コースIDをコースリソースへのGETリンクに置き換えます


これが正解だと思います。mongoにリレーショナルデータを格納しているのでない限り、mongo を使用している理由を疑うべきでした。
ジェイウィック2017年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.