Docs Menu
Docs Home
/ / /
몽고이드
/

상속

이 페이지의 내용

  • 개요
  • 판별자 키 변경
  • 판별자 값 변경
  • 서브클래스 쿼리
  • 연관 관계
  • 지속성 컨텍스트

Mongoid는 최상위 문서와 내장된 문서 모두에서 상속을 지원합니다. 하위 문서가 상위 문서에서 상속되면 상위 문서의 필드, 연결, 검증 및 범위가 하위 문서에 복사됩니다.

class Canvas
include Mongoid::Document
field :name, type: String
embeds_many :shapes
end
class Browser < Canvas
field :version, type: Integer
scope :recent, ->{ where(:version.gt => 3) }
end
class Firefox < Browser
end
class Shape
include Mongoid::Document
field :x, type: Integer
field :y, type: Integer
embedded_in :canvas
end
class Circle < Shape
field :radius, type: Float
end
class Rectangle < Shape
field :width, type: Float
field :height, type: Float
end

위의 예에서 Canvas, BrowserFirefox는 모두 캔버스 컬렉션에 저장됩니다. 데이터베이스에서 로드할 때 올바른 문서가 반환되는지 확인하기 위해 추가 속성 _type이 저장됩니다. 이는 내장된 문서 Circle, RectangleShape에도 적용됩니다.

참고

Circle을 검색할 때 쿼리는 _type(또는 판별자 키가 설정된 값) 필드에 Circle(또는 판별자 값이 설정된 값)이 있는 모양 컬렉션의 문서만 반환하고, 다른 모든 판별자 값은 모양 클래스의 객체로 간주합니다.

마찬가지로 상위 클래스(이 예에서는 Canvas)로 쿼리할 때 컬렉션에서 판별자 값이 없거나 판별자 값이 상위 또는 그 하위 항목에 매핑되지 않는 모든 문서는 상위 클래스의 인스턴스로 반환됩니다.

Mongoid는 기본 _type에서 판별자 키 변경을 지원합니다. 이 작업을 수행해야 하는 경우가 몇 가지 있습니다:

  1. 최적화하려는 경우: _t와 같이 더 짧은 키를 사용할 것을 권장합니다.

  2. 기존 시스템으로 작업하려는 경우: 사용자가 사전 정의된 키가 있는 기존 시스템 또는 데이터세트로 작업하고 있을 수 있습니다.

판별자 키를 변경하는 방법에는 클래스 수준과 전역 수준, 이렇게 두 가지가 있습니다. 클래스 수준에서 판별자 키를 변경하려면 discriminator_key= 메서드를 사용하여 상위 클래스에서 직접 판별자 키를 설정할 수 있습니다. 위의 예를 들어 보겠습니다:

class Shape
include Mongoid::Document
field :x, type: Integer
field :y, type: Integer
embedded_in :canvas
self.discriminator_key = "shape_type"
end
class Circle < Shape
field :radius, type: Float
end
class Rectangle < Shape
field :width, type: Float
field :height, type: Float
end

여기서는 discriminator_key= setter에 대한 호출이 상위 클래스에 추가되었습니다. 이제 Rectangle 또는 Circle을 만들 때 shape_type 필드가 추가됩니다.

판별자 키는 상위 클래스에서만 수정할 수 있으며 하위 클래스에 설정하려고 하면 오류가 발생합니다.

하위 클래스를 만든 후 판별자 키를 변경하면 새 판별자 키 값과 함께 새 필드가 추가되고 이전 필드는 변경되지 않습니다. 예시:

class Shape
include Mongoid::Document
field :x, type: Integer
field :y, type: Integer
embedded_in :canvas
end
class Circle < Shape
field :radius, type: Float
end
class Rectangle < Shape
field :width, type: Float
field :height, type: Float
end
Shape.discriminator_key = "shape_type"

이 경우 Rectangle 또는 Circle을 만들 때 각각 Rectangle 또는 Circle로 기본 설정된 shape_type_type 필드가 둘 다 포함됩니다.

판별자 키는 전역 수준에서도 설정할 수 있습니다. 즉, 모든 클래스가 _type 대신 전역으로 설정된 판별자 키를 사용하게 됩니다. 위의 예를 들어 보겠습니다:

Mongoid.discriminator_key = "_the_type"
class Shape
include Mongoid::Document
field :x, type: Integer
field :y, type: Integer
embedded_in :canvas
end
class Circle < Shape
field :radius, type: Float
end
class Rectangle < Shape
field :width, type: Float
field :height, type: Float
end

전역 판별자 키를 설정한 후 모든 클래스는 _the_type을 판별자 키로 사용하며 _type 필드를 포함하지 않습니다.

전역 수준에서 판별자 키를 정의할 때 하위 클래스가 해당 전역 값을 사용하려면 하위 클래스를 정의하기 전에 먼저 설정해야 합니다. 그러나 전역 수준에서 사용자가 하위 클래스를 정의하기 전에 판별자 키를 설정하지 않으면 판별자 필드에 해당 하위 클래스의 새 전역 설정이 아닌 기본값 _type이 사용됩니다.

Mongoid는 클래스 이름인 기본값에서 판별자 값을 변경하는 것도 지원합니다. 특정 클래스에서 discriminator_value= 메서드를 사용하여 판별자 값을 변경할 수 있습니다.

위의 예를 들어 보겠습니다:

class Shape
include Mongoid::Document
field :x, type: Integer
field :y, type: Integer
embedded_in :canvas
end
class Circle < Shape
field :radius, type: Float
self.discriminator_value = "round thing"
end
class Rectangle < Shape
field :width, type: Float
field :height, type: Float
end

여기서는 discriminator_value= setter에 대한 호출이 Circle에 추가되었습니다. 이제 Circle 생성 시 문서에는 키 _type(또는 discriminator_key가 변경된 항목) 및 값 '둥근 물체(round thing)'가 포함된 필드가 포함됩니다.

참고

판별자 값 재정의는 하위 클래스에서 선언되므로 쿼리에서 찾을 가능성이 있는 하위 클래스를 해당 쿼리를 전송하기 전에 먼저 로드해야 합니다. 위의 예에서 반환된 문서가 잠재적으로 Circle 인스턴스일 수 있는 경우 Shape에서 쿼리할 때 Circle 클래스 정의를 로드해야 합니다(자동 로드는 "round thing"에서 Circle로 해석되지 않기 때문).

하위 클래스에 대한 쿼리는 일반적인 방식으로 처리되며, 문서가 모두 동일한 컬렉션에 있더라도 ActiveRecord의 단일 테이블 상속과 마찬가지로 쿼리는 올바른 유형의 문서만 반환합니다.

# Returns Canvas documents and subclasses
Canvas.where(name: "Paper")
# Returns only Firefox documents
Firefox.where(name: "Window 1")

연결의 일반 설정이나 빌드 및 생성 메서드를 통해 has one 또는 has many 연결에 모든 유형의 하위 클래스를 추가할 수 있습니다.

firefox = Firefox.new
# Builds a Shape object
firefox.shapes.build({ x: 0, y: 0 })
# Builds a Circle object
firefox.shapes.build({ x: 0, y: 0 }, Circle)
# Creates a Rectangle object
firefox.shapes.create({ x: 0, y: 0 }, Rectangle)
rect = Rectangle.new(width: 100, height: 200)
firefox.shapes

Mongoid를 사용하면 하위 클래스의 지속성 컨텍스트를 상위 클래스의 지속성 컨텍스트에서 변경할 수 있습니다. 즉, store_in 메서드를 사용하면 하위 클래스의 문서를 상위 클래스가 아닌 다른 컬렉션(다른 데이터베이스, 클라이언트)에 저장할 수 있습니다.

class Shape
include Mongoid::Document
store_in collection: :shapes
end
class Circle < Shape
store_in collection: :circles
end
class Square < Shape
store_in collection: :squares
end
Shape.create!
Circle.create!
Square.create!

하위 항목에 컬렉션을 설정하면 해당 하위 항목의 문서가 상위 항목의 컬렉션이 아닌 설정된 컬렉션에 저장됩니다.

> db.shapes.find()
{ "_id" : ObjectId("62fe9a493282a43d6b725e10"), "_type" : "Shape" }
> db.circles.find()
{ "_id" : ObjectId("62fe9a493282a43d6b725e11"), "_type" : "Circle" }
> db.squares.find()
{ "_id" : ObjectId("62fe9a493282a43d6b725e12"), "_type" : "Square" }

컬렉션이 일부 하위 클래스에는 설정되어 있고 다른 하위 클래스에는 설정되어 있지 않은 경우, 컬렉션이 설정된 하위 클래스는 해당 컬렉션에 문서를 저장하고 컬렉션이 설정되어 있지 않은 하위 클래스는 상위 컬렉션에 문서를 저장하게 됩니다.

참고

하위 클래스가 저장된 컬렉션을 변경하면 해당 하위 클래스의 문서가 상위 클래스를 쿼리한 결과에 더 이상 포함되지 않을 수 있습니다.

돌아가기

필드 정의