通常のリレーション
1対1
モデル作成
rails g model has_one name:string
rails g model belongs_to name:string
has_one
class HasOne
include Mongoid::Document
field :name, type: String
has_one :belongs_to
end
belongs_to
class BelongsTo
include Mongoid::Document
field :name, type: String
# inverse_ofの指定がないと BelonsTo.first.has_oneの検索が行えない
belongs_to :has_one, :inverse_of => :belongs_to
end
検索
RailsConsole
# HasOneに紐づくBelongsToを取得
HasOne.first.belongs_to
# BelongsToに紐づくHasOneを取得
BelongsTo.first.has_one
追加
RailsConsole
# 個別に作成
HasOne.create(name: "HasOne name")
BelongsTo.create(name: "belongs_to")
# いっぺんに作成
HasOne.create(name: "HasOne name").belongs_to = BelongsTo.create(name: "belongs_to name")
1対多
本と本棚の関連を1対多で表してみる。
モデル作成
Railsコマンド
rails g model book_shelf name:string price:integer
rails g model book name:string price:integer
検索
RailsConsole
# 本棚が複数の本を所持しているので、Arrayで帰ってくる
book_shelf = BookShelf.first.books
# 指定の本がしまってある本棚を取得
books = Book.first.book_shelf
追加
RailsConsole
book_shelf = BookShelf.create(name: "book shelf name", price: 12000)
book_shelf.books.create(name: "book name one", price: 1200)
book_shelf.books.create(name: "book name two", price: 500)
# これでも追加できる
book_shelf.books << Book.create(name: "book name three", price: 300)
多対多
使う場面としてはRDBの中間テーブルを作るような場合に多対多(has_and_belongs_to_many)で定義する。
記事に紐づくカテゴリを例に作成してみる。
モデル作成
Railsコマンド
rails g model Article title:string text:string
rails g model Category name:string slang:string
article.rb
class Article
include Mongoid::Document
field :title, type: String
field :text, type: String
has_and_belongs_to_many :categories
end
category.rb
class Category
include Mongoid::Document
field :name, type: String
field :slang, type: String
has_and_belongs_to_many :articles
end
検索
RailsConsole
# Categoryに紐づくArticleを取得
Category.first.articles
# Articleに紐づくCategoryを取得
Article.first.categories
追加
RailsConsole
# Articleと紐づくCategoryを同時に新規追加
Article.create(title: "article title 1", text: "article text 1").categories.create(name: "category name", slang: "category slang")
# Articleは新規追加を行い既存のCategoryを紐付ける
Article.create(title: "article title 2", text: "article text 2").categories << Category.first
# Article
> db.articles.find().forEach(printjson)
{
"_id" : ObjectId("5638eb5a892bea2b5a000000"),
"title" : "article title 1",
"text" : "article text 1",
"category_ids" : [
ObjectId("5638eb5a892bea2b5a000001")
]
}
{
"_id" : ObjectId("5638ee0d892bea2b5a000002"),
"title" : "article title 2",
"text" : "article text 2",
"category_ids" : [
ObjectId("5638eb5a892bea2b5a000001")
]
}
# Category
> db.categories.find().forEach(printjson)
{
"_id" : ObjectId("5638eb5a892bea2b5a000001"),
"name" : "category name",
"slang" : "category slang",
"article_ids" : [
ObjectId("5638eb5a892bea2b5a000000"),
ObjectId("5638ee0d892bea2b5a000002")
]
}
継承
家族の関連を継承で表してみる。
クラス構造
Family (has_many)
│
Person (belongs_to)
├── Parent
│ ├── Father
│ └── Mother
└── Child
├── Brother
└── Sister
FamilyとPersonは1対多の関係でリレーションが結ばれていて、Person以下は上位のクラスを継承している
モデル作成
Railsコマンド
rails g model Family family_name:string
rails g model Person name:string age:integer
rails g model Parent
rails g model Father
rails g model Mother
rails g model Child
rails g model Brother
rails g model Sister
family
class Family
include Mongoid::Document
field :family_name, type: String
has_many :people
# familyとparentのリレーションを宣言しないと Family.first.parents のように呼べない
has_many :parents
has_many :children
has_many :fathers
has_many :mothers
has_many :sisters
has_many :brothers
end
person
class Person
include Mongoid::Document
field :name, type: String
field :age, type: Integer
belongs_to :family
end
parent
class Parent < Person
include Mongoid::Document
end
mother
class Mother < Parent
include Mongoid::Document
end
father
class Father < Parent
include Mongoid::Document
end
child
class Child < Person
include Mongoid::Document
end
sister
class Sister < Child
include Mongoid::Document
end
brother
class Brother < Child
include Mongoid::Document
end
検索
RailsConsole
# 指定の家族全員を取得
Family.first.people
# 指定の家族の親のみ取得
Family.first.parents
# 指定の家族の子供のみ取得
Family.first.children
# 指定の家族の兄弟のみ取得
Family.first.brothers
追加
newを使う方法
RailsConsole
# 家族を追加
family = Family.create(family_name: "Yamada")
# 家族の人を追加
father = Father.new(name: "father_name", age: 30)
mother = Mother.new(name: "mother_name", age: 29)
brother1 = Brother.new(name: "first_brother_name", age: 6)
brother2 = Brother.new(name: "second_brother_name", age: 4)
sister = Sister.new(name: "first_sister_name", age: 7)
family.people = [father, mother, brother1, brother2, sister]
# families
> db.families.find().forEach(printjson)
{ "_id" : ObjectId("56361e08892bea1af6000006"), "family_name" : "Yamada" }
# people
> db.people.find().forEach(printjson)
{
"_id" : ObjectId("56361e08892bea1af6000007"),
"_type" : "Father",
"name" : "father_name",
"age" : 30,
"family_id" : ObjectId("56361e08892bea1af6000006")
}
{
"_id" : ObjectId("56361e08892bea1af6000008"),
"_type" : "Mother",
"name" : "mother_name",
"age" : 29,
"family_id" : ObjectId("56361e08892bea1af6000006")
}
{
"_id" : ObjectId("56361e08892bea1af6000009"),
"_type" : "Brother",
"name" : "first_brother_name",
"age" : 6,
"family_id" : ObjectId("56361e08892bea1af6000006")
}
{
"_id" : ObjectId("56361e08892bea1af600000a"),
"_type" : "Brother",
"name" : "second_brother_name",
"age" : 4,
"family_id" : ObjectId("56361e08892bea1af6000006")
}
{
"_id" : ObjectId("56361e08892bea1af600000b"),
"_type" : "Sister",
"name" : "first_sister_name",
"age" : 7,
"family_id" : ObjectId("56361e08892bea1af6000006")
}
createを使う方法
RailsConsole
Family.first.sisters.create(name: "build_sister_name", age: 5)
埋め込み型のリレーション
埋め込み (embedds)
モデル作成
rails g model parents name:string
rails g model children parent:references name:string
model/parent.rb
class Parent
include Mongoid::Document
field :name, type: String
embeds_many :children
end
model/child.rb
class Child
include Mongoid::Document
field :name, type: String
embedded_in :parent, :inverse_of => :children
end
追加
RailsConsole
parent = Parent.create(parent_name: "parent_name", parent_age: 24)
# embedds_manyなのでArrayを追加する
parent.children << [
Child.new(child_name: "child_name_1", child_age: 1),
Child.new(child_name: "child_name_2", child_age: 2)
]
> db.parents.find().forEach(printjson)
{
"_id" : ObjectId("562fc7c0892bea15e2000000"),
"parent_name" : "parent_name",
"parent_age" : 24,
"children" : [
{
"_id" : ObjectId("562fc973892bea16cf000000"),
"child_name" : "child_name_1",
"child_age" : 1
},
{
"_id" : ObjectId("562fc978892bea16cf000001"),
"child_name" : "child_name_2",
"child_age" : 2
}
]
}
更新
# childrenはArrayなので、firstやfindでChildクラスを取得してからsave
child = Parent.first.children.first
child.child_name = "child_name_save"
child.save
# update_attributesでも可能
Parent.first.children.first.update_attributes(child_name: "child_name_update", child_age: 1)
削除
RailsConsole
# childrenはArrayなので、firstやfindでChildクラスを取得してからdelete
Parent.first.children.first.delete