开始之前
无论您要配置何种关系,我们建议您按顺序阅读本文档的每个部分,至少一次。这是因为您必须了解 M2O 在 Directus 中如何工作才能了解 O2M,您必须了解 M2O 和 O2M 才能了解 M2M,等等。
概述
Data Studio 通过提供无代码配置,使配置关系数据模型的过程变得更容易、更快、更直观。 Directus 不 对您的数据模型强制执行自以为是的模式、规则系统或其他任意限制。因此,除了项目基础架构的任何技术限制或任何关系数据模型的核心要求,比如为每个集合都有一个主键字段或为每个字段分配一个数据类型, 您可以根据需要自由构建数据模型.
在本指南中,我们将讨论以下主题:
- Directus 中存在哪些类型的关系。
- 如何在 Data Studio 中配置所需的关系。
- 如何在数据模型中实现关系并在 Data Studio 中显示。
- 何时可能适合使用给定类型的关系。
最后,您将了解开始在 Directus 中构建数据模型所需的一切,即使关系数据模型概念对您来说是一个新概念。
Directus 与经典数据模型术语
当我们使用经典的数据模型术语时,如数据表、列、行等...... 这表明解释严格集中在数据库中发生的事情上。当使用 Directus 术语时,如集合、字段、项目等...... 这表明解释包括 Directus 逻辑和功能。
多对一 (M2O)
在 M2O 关系中,父集合中的多个项目链接到相关集合中的一个项目。 例如,一个国家有很多城市,但一个城市只能在一个国家。
为了创建 M2O 关系,我们向父集合添加一个外键字段,它将父集合中的项目链接到相关集合中的项目。 如果我们有两个表,cities
和 countries
,我们可以创建一个 cities.country_id
外键字段。
让我们看一下架构。
cities
- id
- name
- country_id (外键字段,存储来自 countries.id 的键)
countries
- id
- name
请注意上述架构中的以下内容:
- M2O 关系只需要父表中的一列。
- 在 Directus 中配置 M2O 关系字段时,父集合上的项目页面将允许访问相关集合中的项目。 因此,在我们上面的示例中,
cities
中的项目页面将允许从countries
表访问相关国家。
但是,在 Directus Data Studio 中,M2O 字段不会自动提供对相关集合中父集合项目的访问。 在我们的示例中,这意味着当您在“国家/地区”中打开项目页面时,您将看不到相关城市。
这就是 O2M 领域发挥作用的地方。
配置 M2O
配置 M2O 字段的最简单方法是遵循如何创建字段(标准)的指南并从 模板向导。
一对多 (O2M)
在关系数据库中,O2M 关系与 M2O 的关系类型完全相同。 请记住,在 M2O 部分的末尾,我们了解到在 Directus 中配置 M2O 不允许我们访问相关集合上的项目页面中的相关项目。 在 Directus 中,配置 O2M 会创建一个 Alias 字段,让我们可以访问相关项目。 为了证明这一点,让我们继续使用 M2O 部分中使用的“城市”和“国家”示例关系。
让我们看一下架构。
countries
- id
- name
- cities
(O2M 别名字段,在数据表中不存在。 允许访问与一个国家/地区相关联的所有城市。)
cities
- id
- name
- country_id (the M2O field)
请注意上述架构中的以下几点。 当我们在 Directus 中创建 O2M 时:
- 由于视角被翻转,我们现在将“国家”视为父集合。
- 创建 O2M 并不总是必要的。 在某些情况下,您不希望或不需要从双方访问项目。
- 乍一看,这个 O2M 别名字段可能会 看起来和感觉 就像创建了一个新列,但 O2M 字段是纯粹的 虚拟。 它在 Data Studio 中创建一个界面,以从 O2M 角度访问项目。 换句话说,O2M 别名字段允许我们从“国家”集合中的项目详细信息页面中的“城市”访问任何相关项目。
配置 O2M
配置 O2M 的最简单方法是遵循有关如何 创建字段(标准)的指南并从模板向导。
一对一 (O2O)
Directus 不包括专用的一对一 (O2O) 关系类型或接口。但是,在数据库中,O2O 与 M2O 几乎完全一样。唯一的区别是 O2O 强制执行 cardinality。换句话说,父集合中的一项可以与相关集合中的一项链接,反之亦然。
例如,每个国家都有一个首都,反之亦然。这是一个O2O。为了演示它是如何工作的,让我们将此 O2O 添加到前面部分中使用的“城市”和“国家”示例关系中。
您可能会想到的第一个策略是在 countries
集合上添加一个新的 capital_city
字段,直接存储首都的名称。但这会产生重复数据,因为同一个城市会同时存在于countries.capital_city
和cities.name
中。但请记住,我们要 避免重复数据!
相反,我们想使用 O2O 关系。让我们尝试添加一个 cities.capital_of
字段。
让我们看一下架构。
cities
- id
- name
- country_id
- capital_of
(O2O字段。 实际上是一个 M2O,配置为存储唯一值,存储来自 countries.id 的外键)
countries
- id
- name
- cities
上述模式中的 O2O 关系有效,在某些情况下,将 O2O 配置到哪个集合上可能并不重要。 但在这种情况下,它是次优的。 由于 大多数城市 不是首府城市,该列将主要包含“NULL”值。 但是,每个国家都有首都。 所以如果我们在countries
集合上创建O2O,效率会高很多。
让我们看一下架构。
countries
- id
- name
- cities
- capital_city
(O2O字段,实际上是一个 M2O,配置为存储唯一值,存储来自 citys.id 的外键)
cities
- id
- name
- country_id
请注意上述架构中的以下几点。 当我们在 Directus 中创建 O2O 时:
- 我们可以在任一集合上添加 O2O 字段。 但是,在某些情况下,将其添加到特定集合中会更有效。
- 由于O2O字段实际上只是幕后的M2O字段,并且由于Directus不会自动显示相关集合中的M2O字段,您可能需要配置一个O2M字段 这样您也可以访问相关集合中的项目。
多对多 (M2M)
到目前为止我们看到的关系类型只需要一个外键列来链接父集合和相关集合。 M2M 关系由 由两个外键列 组成,存储在一个名为 junction table 的附加表中,该表存储父表和相关表之间的每个链接行。
M2M 关系中需要连接表,因为创建的关系数可能 (而且通常会!) 超过任一数据表中的行数。换句话说,如果父列中有“x”行,相关列中有“y”行,则需要空间来存储最多“x * y”行。联结表提供了一个存储行之间所有关系的地方,无论存在多少。
为了证明这一点,让我们考虑一下食谱和配料之间的关系:一个 食谱 可以有许多 配料,而 配料 可以在许多 食谱 中。
让我们看一下架构。
recipes
- id
- name
- ingredients
(M2M 别名字段。 数据库中不存在,允许访问从 recipe_ingredients 链接的成分)
recipes_ingredients (交汇点集合)
- id
- recipe (存储来自 recipes.id 的外键)
- ingredient (存储来自 ingredients.id 的外键)
- quantity (“上下文”字段。 存储与关系关联的其他数据。 这些是可选的。)
ingredients
- id
- name
请注意上述架构中的以下几点。 当我们在 Directus 中创建 M2M 时:
- 我们的联结集合,
recipe_ingeredients
,每行包含两个外键列。 这就是创建两个表之间关系的原因。 - 假设 M2M 别名字段是在“recipes”集合中创建的,Directus 不会自动添加字段来显示“配料”集合中的食谱。 但是,如果需要,您可以在
ingredients
中配置别名字段:
ingredients
- id
- name
- recipes
(数据库中不存在的 O2M 别名字段,可以访问与成分相关的所有配方)
- 请注意,junction 集合还有一个“数量”字段,用于跟踪配方所需的每种成分的数量。 这称为_上下文字段_。 Data Studio 提供对联结集合的完全访问权限,因此您可以向联结集合添加任意数量的上下文字段。
- 您还可以拥有连接_相同集合_中的项目的自引用 M2M 关系。 一个例子是“相关文章”,其中每篇文章都与许多其他文章相关。
配置 M2M
配置 M2M 的最简单方法是遵循有关如何 创建字段(标准) 的指南并选择 多对多 来自模板向导。
多对任意 (M2A)
有时称为 matrix field 或 replicator,M2A 关系允许您将父集合中的项目链接到数据库中任何集合中的任何项目。 当您在 Directus 中配置 M2A 时,会创建一个 M2A 别名 字段以及一个连接集合,就像我们在 M2M 关系中看到的那样。 不同之处在于,M2A 上的联结集合也有一个字段来存储相关集合的集合键 (集合的名称)。
使用 M2A 的一个常见示例是 page builder,它有一个 pages
集合,该集合为每种类型的页面部分组合了多个集合,例如 heading
、text_bodies
、image
、video
、等等 .
让我们看一下架构:
pages
- id
- name
- sections
(数据库中不存在 M2A 别名字段。 提供对 page_sections 中项目的访问。)
page_sections (junction collection)
- id
- pages_id
(一个 M2O,存储 pages.id 中的外键)
- collection
(M2O,存储相关集合的名称,例如标题、text_bodies 或图像。)
- item
(一个 M2O,存储来自 headings.id、text.id、images.id 等的外键。)
headings
- id
- title
text_bodies
- id
- text
images
- id
- file
请注意上述架构中的以下几点。 当我们在 Directus 中创建 M2A 时:
- 与 M2O 和 M2M 关系相比,您可能需要在相关集合上配置别名字段的可能性较低,例如
headings
、text_bodies
和images
,因为这些集合可能没有那么有用 父集合。 - 每个集合都有一个唯一的集合名称,因此它可以作为
page_sections.collection
字段中的足够外键。
配置 M2A
配置 M2A 的最简单方法是遵循有关如何 创建字段(标准) 的指南并选择 **Many to Any ** 模板向导的界面。
翻译 (O2M)
Directus 提供了这种专门用于处理翻译的特殊关系接口。当您在 Data Studio 中创建 Translations O2M 时,您的数据模型中会发生以下情况。将创建 Translations O2M 别名字段。创建一个联结集合和一个“语言”集合。您的所有翻译都存储在您配置的联结集合上的上下文字段中。因此,当您创建 Translations O2M 时,您也在幕后创建了 M2M 关系。所以请记住,它之所以称为 Translations O2M,是因为我们与 Translations O2M 别名字段进行交互。但在幕后,它是由 M2M 驱动的。
为了演示,让我们为“文章”创建一个翻译 O2M 关系,这是一种您可能想要翻译的常见内容类型。
让我们看一下架构。
articles
- id
- author (未翻译的字段)
- date_published (未翻译的字段)
- translations (数据表中不存在 Translations O2M 别名字段。 允许访问 article_translations 中的项目)
article_translations
- id
- article_id (一个 M2O,存储外键 article.id)
- language_id (一个M2O,存储外键language.language_code)
- title (由您创建的上下文字段。 存储文章标题的翻译)
- text (由您创建的上下文字段。 存储您创建的文章 TitleaA 上下文字段的翻译。 存储文章文本的翻译)
languages
- language_code (一个主键。 手动输入的语言代码,例如“en-US”)
- name (存储语言名称,例如“English”)
请注意上述架构中的以下几点。当我们创建翻译 O2M 时:
- 正如
article_translations.title
和article_translations.text
所示,任何 translated 字段都应作为上下文字段添加到联结集合中。 - 您不必将其用于翻译。您可以根据需要构建数据模型。您可以为每个翻译创建单独的字段,例如
title_english
、title_german
、title_chinese
等。但是,这并不容易扩展,并且它创建了一种次优体验,即在项目详细信息页面上对每个字段进行每个单独的翻译。 Translations O2M 别名字段专为简化翻译过程而设计。 - 有时您可能希望使预先存在的父字段可翻译。为此,您可以复制一个字段,将其移动到翻译集合中,然后删除父字段。但是,请注意复制字段 不 复制任何现有字段值。
配置翻译 O2M
配置翻译关系的最简单方法是遵循如何创建字段(标准)的指南并选择 Translations O2M 模板向导的界面。