2017-04-24 1 views
0

부모가 ProductCategory이고 자식이 Product입니다. 예를 들면 : ProductCategory 주어진 옵션문자열 화 된 데이터를 효율적으로 검색하려면 어떻게해야합니까?

ProductCategory --- Product 
      Drill --- DeWalt DWD 112 
       --- Black & Decker 5 C 
     Bicycle --- Motobecane Turino ELITE Disc Brake 
       --- Shimano Aluminum 

모든 Products가 서로 비교되어야 속성 집합이있다 (즉, 데이터를 가지고). 그러나이 속성 집합은 ProductCategories

과 같이 다를 수 있습니다. 예를 들어 드릴의 ProductCategory의 경우 속성은 Voltage, Amps, Corded vs Cordless 일 수 있습니다. Every Product 드릴에 이러한 정보가 있어야합니다. 그러나 자전거의 ProductCategory의 경우 속성은 Size, Road vs Mountain이어야하고 모든 Product 자전거는이 정보가 있어야합니다. (드릴 또는 자전거에 대해 아무것도 모르는 죄송합니다 ... 내가 이것을 골랐다는 이유는 어리 석다)

주어진 Product에 대해 DB를 설계하려고하는데, 그 속성은 내가 쉽게 할 수있는 것이다. 수색. 예를 들어, 이상적으로는이 명령을 실행할 수 있습니다 심지어,이 후 나는 Product 모든 ProductCategory에 대한 모든 속성에 대한 열을 가지고해야 할 것 때문에 ... 흥미로운 트레이드 오프를 제시하는 것

drills = Product.where(product_category_id:1) 
drills.where("voltage >= ?", 5) 
-> returns the individual drills, which may include DeWalt but not Black & Decker 

을 그 그것과 관련이 없다. 예를 들어 :

# Product columns 
:voltage, :integer #for Drill 
:amps, :integer #for Drill 
:corded, :boolean #for Drill 
:size, :integer #for Bicycle 
:mountain, :boolean #for Bicycle 
... 

이 지속하지 않는 것 ... 당신은 ProductCategories에 대한 몇 가지 곧 Product 열 무한한 수있을 것이라는 점을 매우 신속하게 볼 수 있습니다!

# ProductCategory has a column... 
:required_attributes, :text 

ProductCategory.where(name:"Drill").first.required_attributes 
-> "voltage,amps,corded" 

ProductCategory.where(name:"Bicycle").first.required_attributes 
-> "size,mountain" 

# Product has a column... 
:attribute_data, :text 

Product.where(name:"DeWalt").first.attribute_data 
-> "{'voltage':5,'amps':5,'corded':5}" 

함께 : 스펙트럼의 타단

, 나는 캐릭터 데이터로서 Product 그들을 저장/이러한 특성을 요구하는 다음 상위 ProductCategoryProduct 요구 정의하는 특성을 갖는 한 생각 위의 디자인을 적용하면, Product 생성시마다 required_attributes에 대한 정보를 쉼표로 분할 한 후에 정보를 제공해야한다는 프런트 엔드를 만들 수 있습니다. 그러나 물론 이것은 검색 효율성을 떨어 뜨립니다. 최소한 그것이 그렇다고 생각합니다. 그래서 이것이 제 질문입니다. 문자열 화 된 데이터를 효율적으로 검색하려면 어떻게해야합니까? 최소 5 볼트 이상의 모든 드릴을 검색하려면 아래를 완료하십시오.

drills = ProductCategory.where(name:"Drill") 
drills.where("attribute_data ...") 
+0

업데이트 된 답변보기 –

+0

정말 좋은 답변이 아니므로 내 대답을 삭제했습니다. 그러나 이것은 매우 광범위하게 SO에서 대답 할 수있는 질문이 아니며 EAV 테이블 및 JSON 열과 같은 기존 패턴에 대한 지식이 약간 필요합니다. – max

+0

나는 그 @max를 얻는다. 그러나 나는 그 안에서 참조가 유용하다는 것을 발견한다. 나는이 넓은 주제를 탐구하고있다. 코멘트로 다시 게시 하시겠습니까? – james

답변

0

가장 간단한 해결책은 사양을 저장 productsJSON or HSTORE 데이터 유형의 열을 사용하는 것이다.

그러나 당신은 당신이 조인 테이블 디자인을 사용할 수 있습니다 사양에 따라, 좀 더 제어 및 검증 갖고 싶어 : 그 것 같은 디자인을 사용하여 클래식 문제의

class Product 
    has_many :specs 
    has_many :definitions, through: :specs 
end 

# This is the "normalized" table that defines an specification 
# for example "Size". This just holds the name for example and the acceptable values. 
class Definition 
    has_many :specs 
    has_many :products, through: :specs 
end 

# this contains the actual specs of a product (the value) 
# specs.payload is a JSON column 
class Spec 
    belongs_to :definition 
    belongs_to :product 
    delegate :name, to: :definition 

    def value 
    payload[:value] 
    end 

    def value=(val) 
    payload[:value] = val 
    end 
end 

하나를 specs 테이블은 값을 텍스트 (또는 varchar) 열로 저장하고 형식 변환 문제를 처리해야합니다. 하지만 대부분의 현대 DB는 HSTORE 나 JSON과 같은 동적 컬럼 타입을 지원하여 실제 값을 저장할 수 있습니다.이것은 안티 패턴 일 수 있지만, 종종입니다 수있는 Entity–attribute–value model을 소위에 정규화 된 변화의 일종이다

Spec.where("payload->>'value' = ?", "foo") 

:

단점은 쿼리 할 때 당신이 특별한 SQL 구문을 사용해야한다는 것입니다 관계형 데이터베이스의 동적 속성에 대한 유일한 해결책입니다.

참조 :

+0

정말 도움이됩니다. 잠깐 NoSQL에 빠져들고 싶었 기 때문에 JSON 데이터 유형을 사용하게되었습니다. 이 대답들 중 하나를 지우지 마십시오! 나중에 읽을 가능성이 높습니다. – james

0

EAV 테이블의 문제를 방지 문제에 접근하는 또 다른 방법은 멀티 테이블 상속을 사용하는 것입니다. 이 예제에서는 ActiveRecord :: ActsAs를 사용합니다.

class Product < ActiveRecord::Base 
    actable 
    belongs_to :brand 
    validates_numericality_of :universal_product_code, length: 12 
    validates_presence_of :model_name, :price 
end 

class Bicycle < ActiveRecord::Base 
    acts_as :product 
    validates_numericality_of :gears 
    validates_presence_of :size 
end 

class PowerTool < ActiveRecord::Base 
    acts_as :product 
    validates_numericality_of :voltage, :amps 
    validates_presence_of :voltage, :amps 
end 

이것은 products 테이블에 기본 정보를 저장하는 것입니다 :

change_table :products do |t| 
    t.decimal :price 
    t.sting :model_name 
    t.integer :universal_product_code, length: 12 
    t.integer :actable_id 
    t.string :actable_type 
end 

를 그리고보다 구체적인 테이블에 제품의 아형을 저장하는 다형성 연관을 사용

create_table :bicycles do |t| 
    t.integer :gears 
    t.integer :size 
end 

create_table :power_tools do |t| 
    t.boolean :corded 
    t.integer :amps 
    t.integer :size 
end 

장점은 느슨한 속성 대신 정의 된 스키마가 있음을 의미합니다. 단점은 일반 웹 샵을 디자인 할 때 고정 된 스키마가이를 잘라 내지 않는 경우입니다.

관련 문제