Postgres и Ruby — Есть ли лучший способ структурировать мою базу данных?

#ruby-on-rails

#ruby-on-rails

Вопрос:

Я планирую свою базу данных прямо сейчас. И в процессе объединения моего ERD я быстро заметил, что все таблицы связаны КАК с моей shops таблицей, так и с моей amazon_credentials таблицей. Есть ли лучший / более эффективный дизайн или взаимосвязь, которые я могу внедрить, чтобы сделать мою базу данных более эффективной и простой в использовании?

Вот ссылка на мой текущий ERD в Whimsical

Еще одно предостережение: я не хочу проходить через свою amazon_credentials таблицу для всех запросов. Например.. Я хотел бы иметь возможность делать и то Shop.find(1).packing_slips , и другое, и получать все packing_slips для a shop , а также иметь возможность делать это Shop.find(1).amazon_credentials.packing_slips , чтобы получить packing_slips для определенного рынка.

Размышляя об этом, я почти использую свою amazon_credentials таблицу в качестве дублера, marketplace поскольку учетные данные по своей сути ограничены marketplace

Это хороший дизайн или есть лучший способ?

Комментарии:

1. У вас есть это, чтобы магазин мог использовать 0 или более учетных данных Amazon. Это то, что вы хотите?

2. Вы используете Rails? » Я не хочу проходить через мою таблицу amazon_credentials для всех запросов » Почему бы и нет?

3. @Schwern привет .. да, используя Rails.. и да shop , может быть 0 или больше amazon_credentials

4. Если у магазина может быть много AmazonCredentials, как вы узнаете, какой использовать?

5. @Schwern это основано на адресе клиентов в order . the marketplace в пределах amazon_credentials конкретных стран. и на основе адреса клиента используется правильный набор учетных данных..

Ответ №1:

Дублированные связи с магазинами и AmazonCredentials, разбросанные по базе данных, можно заменить косвенными связями. К счастью, Rails предоставляет методы, позволяющие сделать косвенные отношения прямыми: has_many :through .

И вам не нужно доводить ее до совершенства с первого раза или прогнозировать все возможные варианты использования. Миграции помогают безопасно изменять дизайн в соответствии с меняющимися требованиями.

Давайте построим основные взаимосвязи. Я сделал некоторые предположения, например, методы доставки привязаны к торговой площадке.

  • Продукт содержит информацию о себе.
  • В магазине есть продукты, способы их продажи (торговая площадка), учетные данные для этих торговых площадок и заказы.
  • В заказе указывается, кто сделал заказ, из какого магазина, через какую торговую площадку, какие продукты были заказаны и сколько по какой цене, как они отправляются и как их отслеживать.
  • На торговой площадке есть методы доставки.

Сразу же мы сталкиваемся с проблемой: учетные данные. Магазину нужны учетные данные для каждой торговой площадки. Это решается с помощью промежуточной модели: MarketplaceAccount, которая объединяет магазин и маркетплейс с учетными данными магазина. Учетные данные могут быть преобразованы в строки пар ключ / значение.

В заказе необходимо помнить подробности о том, какие продукты были заказаны, сколько и на какую сумму. Для этого нужна еще одна промежуточная модель: ProductOrder.

Базовые модели будут выглядеть примерно так:

 class Product < ApplicationRecord
  belongs_to :shop

  has_many :product_orders
  has_many :orders, through: :product_orders
  has_many :customers, through: :orders

  # name
  # description
  # sku
end

class Shop < ApplicationRecord
  has_many :products

  has_many :marketplace_accounts
  has_many :marketplaces, through: :marketplace_accounts
  
  has_many :orders
  has_many :customers, through: :orders

  # name
  # country
end

class Order < ApplicationRecord
  belongs_to :customer

  # Remember which MarketplaceAccount this was done with
  belongs_to :marketplace_account
  has_one :shop, through: :marketplace_account
  has_one :marketplace, through: :marketplace_account

  # How is it being shipped?
  belongs_to :shipping_method
  
  has_many :product_orders
  has_many :products, through: :product_orders

  # tracking number
  # status
end

class ProductOrder < ApplicationRecord
  belongs_to :order
  belongs_to :product

  # price
  # quantity
end

# Holds the Shop's credentials for a Marketplace.
class MarketplaceAccount < ApplicationRecord
  belongs_to :shop
  belongs_to :marketplace
  has_many :credentials
end

# Each row is simply a key and value.
# Consider encrypting this table.
class Credentials < ApplicationRecord
  belongs_to :marketplace_account

  # key
  # value
end

class Marketplace < ApplicationRecord
  has_many :shipping_methods

  has_many :marketplace_accounts
  has_many :shops, through: :marketplace_accounts

  # name
end

class ShippingMethod < ApplicationRecord
  belongs_to :marketplace
  has_many :shops, through: :marketplace

  # speed
  # rate
  # name
end

class Customer < ApplicationRecord
  has_many :orders
  has_many :product_orders, through: :orders
  has_many :products, through: :product_orders
end
 

Используя has_many :through и has_one :through , мы можем избежать дублирования, делая косвенные отношения кажущимися прямыми. У магазина есть множество учетных записей MarketplaceAccounts, учетная запись MarketplaceAccount принадлежит торговой площадке; при has_many :marketplaces, through: :marketplace_accounts этом магазин может напрямую обращаться к своим торговым площадкам. shop.marketplaces .

Таблица учетных данных ключ/значение позволяет избежать увеличения количества таблиц учетных данных, специфичных для конкретной компании.


Можно конкретизировать больше взаимосвязей. Продукт может продаваться многими магазинами, поэтому у нас может быть ShopProduct, который связывает универсальный продукт с тем, как его продает Магазин. Это позволяет избежать дублирования информации о продукте и позволяет увидеть, как один продукт продается во многих магазинах.

 class Product < ApplicationRecord
  has_many :shop_products

  # sku
  # generic name
  # generic description
  # manufacturer's recommended price
end

class ShopProduct < ApplicationRecord
  belongs_to :shop
  belongs_to :product

  delegate :sku, to: :product

  # shop specific name
  # shop specific description
  # shop price
end

class Shop
  has_many :shop_products
  has_many :products, through: :shop_products
end
 

И большинство вещей будут относиться к Товару, а не к Продукту.


У вас есть магазин, работающий с единой валютой. Дизайн может быть расширен, чтобы позволить магазину работать со многими валютами.

 class Currency < ApplicationRecord
  # symbol
  # conversion rate
end

class ShopCurrencies < ApplicationRecord
  belongs_to :shop
  belongs_to :currency
end

class Shop < ApplicationRecord
  has_many :shop_currencies
  has_many :currencies, through: :shop_currencies
end
 

has_many :currencies, through: :shop_currencies давайте shop.currencies работать.


Это основы. Вооружившись этим, вы можете настроить базовый макет в соответствии с вашими потребностями.

Комментарии:

1. большое спасибо за подробный ответ!