Как версионировать записи таблицы в базе данных?

У меня есть таблица в базе данных, в которой хранятся продукты для покупки (назовем таблицу Product). Необходимо отслеживать изменения каждого продукта. У меня есть 2 идеи для версий записей.

Во-первых, создать новую запись в Product, скопировав продукт и переопределив поля, которые отличаются, и сохранить ссылку в записи для более старой и новой версии. В этом случае запись в таблице «Товары» доступна только для чтения, за исключением поля, указывающего, находится ли продукт в архиве или нет.

Во-вторых, создать 2 таблицы: Product и ArchivisedProduct. Записи продукта редактируются, но для каждого изменения создается новая запись в ArchivisedProduct, где хранятся только различия (поэтому, кроме идентификатора, все поля могут быть пустыми), а поля таблиц содержат ссылки друг на друга.

Знаете ли вы какой-нибудь инструмент, который может управлять этим процессом и хорошо работает с Node.js, Prisma, PostgreSQL и Apollo? Для такого использования мне был рекомендован winston/papertrail, но, когда я читал документы, кажется, что он только создает журналы.

Примерная структура базы данных для большего понимания: 1-й пример:

type Product {
  id: Int! @id
  name: String!
  price: Float!
  archived: Boolean!
  productVersionIds: [Product]!
}

2-й пример:

type Product {
  id: Int! @id
  name: String!
  price: Float!
  archivisedProductIds: [ArchivisedProduct]! @relation(name: "ProductToArchiva")
}

type ArchivisedProduct {
  id: Int! @id
  name: String
  price: Float
  product: Product! @relation(name: "ProductToArchiva")
}

person Dune    schedule 07.04.2020    source источник


Ответы (1)


В зависимости от того, сколько продуктов вы собираетесь хранить, может быть проще хранить каждую версию продукта в модели ProductVersion, а затем следить за последним продуктом («головой») в модели Product.

У вас будет:

type ProductVersion {
  id: Int! 
  version: Int!
  name: String!
  price: Float!

  @@id([id, version])
}

type Product {
  productId: Int! @id
  headVersion: Int!
  productVersion: Product! @relation(fields: [productId, headVersion], references: [id, version])
}

Для каждого изменения продукта вы должны хранить новый ProductVersion, содержащий информацию, и обновлять соответствующий Product, чтобы указать headVersion на новый ProductVersion. Все это будет частью одной транзакции для обеспечения согласованности.

Чтобы запросить список продуктов, вы должны использовать объект Product и присоединиться к ProductVersion. Если вы храните много продуктов и объединение вызывает беспокойство, вы можете подумать о том, чтобы скопировать все данные ProductVersion в поле Product вместо использования отношения через поле headVersion.

Обратите внимание, что это также будет означать, что вы будете вычислять diff во время выполнения, а не хранить их непосредственно в самой базе данных.

person Hervé Labas    schedule 08.04.2020