Firebase 中Firestore中的结构化数据属于并具有许多关系

Firebase 中Firestore中的结构化数据属于并具有许多关系,firebase,react-native,google-cloud-firestore,Firebase,React Native,Google Cloud Firestore,来自SQL/Rails背景的我有一个项目,我想与React一起使用Firebase/Firestore,并请求帮助设置数据和收集结构 型号: 使用者 项目 类别 位置 一个用户可以有许多项,并且一个项属于一个用户。 一个类别可以有许多项,并且一个项属于一个类别 我需要能够显示在主页上的所有类别,位置和项目。 首先,我需要列出所有项目,它们可以按类别和/或位置进行过滤 如何在Firestore中最好地设置这些数据 对于rails风格的解释,我感到很抱歉,但是SQL在我的脑海中无处不在。我想您是在考

来自SQL/Rails背景的我有一个项目,我想与React一起使用Firebase/Firestore,并请求帮助设置数据和收集结构

型号:

使用者 项目 类别 位置 一个用户可以有许多项,并且一个项属于一个用户。 一个类别可以有许多项,并且一个项属于一个类别

我需要能够显示在主页上的所有类别,位置和项目。 首先,我需要列出所有项目,它们可以按类别和/或位置进行过滤

如何在Firestore中最好地设置这些数据

对于rails风格的解释,我感到很抱歉,但是SQL在我的脑海中无处不在。

我想您是在考虑SQL DB中的外键。nosql场景中通常发生的情况是,您应该避免使用关系,而是将关系展平为nosql中的一个大document document=json对象

这方面没有具体的回应

亚历克斯试图解释的是,你应该考虑哪一个是你的设计中的核心元素。似乎这就是“项目”元素

一种可能的设计可以是:

将类别和位置以普通格式存储到表示项目的json对象中

然后使用数组列出前端中的项目

最后,使用前端的JS array.filter函数过滤响应用户操作所显示的内容

如果您只需要显示属于用户的项目,请在“项目”文档中添加“用户”字段,并要求firestore仅返回“用户”字段与您登录的用户匹配的文档

这有点过时,但应该可以帮助您理解nosql中的数据非规范化:

编辑 关于Jay answer和评论中提到的MongoDB文章,我一直很难做出决定:如果嵌入数据或引用数据,但我总是嵌入小文档

你能分享你的经验吗

我总是觉得在前端创建额外的查询来重新加入所需的info a-la sql非常无聊,而在指向其他小文档方面,我几乎没有优势。我想这主要取决于应用程序的设计

总之

我喜欢这样的东西

用户\u集合>用户\u uuid\u 0 { 姓名:约翰 项目:[ {/*…此处为普通item1对象…*/}, {/*…此处为普通item2对象…*/}, /*...*/ ] } 而不是:

用户\u集合>用户\u uuid\u 0 { 姓名:约翰 项目编号:[ 项目_uuid_0, 第1项, /*...*/ ] } -- 项目集合>项目1 { /*所有项目字段*/ 属于:用户\u uuid\u 0 } 项目集合>项目2 { /*所有项目字段*/ 属于:用户\u uuid\u 0 } 后一种解决方案的好处是更具灵活性和解耦性:您可以在不影响项目的情况下更改用户详细信息,如果流量大小比服务中的运营商数量更重要,则有效负载更小

缺点是:需要2次查询DB 1以获取用户文档,1次查询以获取按id过滤的项目,而不是仅1次;它需要在前端执行大量操作来重新收集所有内容,而不是添加任何操作,因为以前的文档布局已经嵌入了所有内容

如果满足以下条件,则前者效果良好:

你有一对几的关系,一对多倾向于像Jay建议的uuid裁判 您的文档很小,否则Jay的解决方案会更好 如果您是按运营而不是按流量大小计费 当我们考虑像firestore这样的托管nosql数据库时,通常 CRUD API基本上是一个REST API或与之相当接近的东西,没有JPA、DTO投影等等。。。根据我的经验,第一种布局更适合

但是,同样,这主要与应用程序设计和服务成本有关。

我想您考虑的是sql DB中的外键。nosql场景中通常发生的情况是,您应该避免使用关系,而是将关系展平为nosql中的一个大document document=json对象

这方面没有具体的回应

亚历克斯试图解释的是,你应该考虑哪一个是你的设计中的核心元素。似乎这就是“项目”元素

一种可能的设计可以是:

将类别和位置以普通格式存储到表示项目的json对象中

然后使用数组列出前端中的项目

最后,使用前端的JS array.filter函数过滤响应用户操作所显示的内容

如果您只需要显示属于用户的项目,请在“项目”文档中添加“用户”字段,并要求firestore仅返回“用户”字段与您登录的用户匹配的文档

这有点过时,但应该可以帮助您理解nosql中的数据非规范化:

编辑 关于Jay answer和评论中提到的MongoDB文章,我已经 ys很难做出决定:是否嵌入数据或引用数据,但我总是嵌入小文档

你能分享你的经验吗

我总是觉得在前端创建额外的查询来重新加入所需的info a-la sql非常无聊,而在指向其他小文档方面,我几乎没有优势。我想这主要取决于应用程序的设计

总之

我喜欢这样的东西

用户\u集合>用户\u uuid\u 0 { 姓名:约翰 项目:[ {/*…此处为普通item1对象…*/}, {/*…此处为普通item2对象…*/}, /*...*/ ] } 而不是:

用户\u集合>用户\u uuid\u 0 { 姓名:约翰 项目编号:[ 项目_uuid_0, 第1项, /*...*/ ] } -- 项目集合>项目1 { /*所有项目字段*/ 属于:用户\u uuid\u 0 } 项目集合>项目2 { /*所有项目字段*/ 属于:用户\u uuid\u 0 } 后一种解决方案的好处是更具灵活性和解耦性:您可以在不影响项目的情况下更改用户详细信息,如果流量大小比服务中的运营商数量更重要,则有效负载更小

缺点是:需要2次查询DB 1以获取用户文档,1次查询以获取按id过滤的项目,而不是仅1次;它需要在前端执行大量操作来重新收集所有内容,而不是添加任何操作,因为以前的文档布局已经嵌入了所有内容

如果满足以下条件,则前者效果良好:

你有一对几的关系,一对多倾向于像Jay建议的uuid裁判 您的文档很小,否则Jay的解决方案会更好 如果您是按运营而不是按流量大小计费 当我们考虑像firestore这样的托管nosql数据库时,通常 CRUD API基本上是一个REST API或与之相当接近的东西,没有JPA、DTO投影等等。。。根据我的经验,第一种布局更适合


但是,同样,这主要与应用程序设计和服务成本有关。

这是一种过于简单的方法,但它确实满足了问题中概述的要求

您将需要四个集合,一个用于问题中提到的每个类别,然后每个集合中的文档将包含关于该项目的信息以及对该文档“拥有者”的引用

Users
   uid_0
      name: "Kirk"
   uid_1
      name: "McCoy"
   uid_2
      name: "Spock"

Items
   item_0
      name: "Communicator"
      belongs_to_user: uid_0
      category: "cat_0"
      location: "location_3"
   item_1
      name: "Tricorder"
      belongs_to_user: "uid_1"
      category: "cat_0"
      location: "location_2"
   item_2
      name: "Captains Chair"
      belongs_to_user: "uid_0"
      category: "cat_2"
      location: "location_0"
   item_3
      name: "Science station"
      belongs_to_user: "uid_2"
      category: "cat_1"
      location: "location_0"

Categories
   cat_0
      name: "Hand held devices"
   cat_1
      name: "Stations"
   cat_2
      name: "Furniture"

Locations
   location_0
      name: "Bridge"
   location_1
      name: "Engine Room"
   location_2
      name: "Sick Bay"
   location_3
      name: "Shore leave"
一个用户可以有许多项,并且一个项属于一个用户

用户数据存储在用户集合中,documentId是用户ID。在上面的示例中,用户Kirk uid_0有两个项目,项目_0 a communicator和项目_2 a captains chair。同样,用户McCoy有一个tricorder和一个科学站Spock

一个类别可以有许多项,并且一个项属于一个类别

在本例中,我们有三个类别,通信器和Tricorder都属于cat_0手持式设备

首先,我需要列出所有项目,它们可以通过 类别和/或位置


上述结构将使您能够获得所有项目的列表。然后可以按用户、所属类别和位置对其进行筛选。

这是一种过于简单的方法,但它确实满足了问题中概述的要求

您将需要四个集合,一个用于问题中提到的每个类别,然后每个集合中的文档将包含关于该项目的信息以及对该文档“拥有者”的引用

Users
   uid_0
      name: "Kirk"
   uid_1
      name: "McCoy"
   uid_2
      name: "Spock"

Items
   item_0
      name: "Communicator"
      belongs_to_user: uid_0
      category: "cat_0"
      location: "location_3"
   item_1
      name: "Tricorder"
      belongs_to_user: "uid_1"
      category: "cat_0"
      location: "location_2"
   item_2
      name: "Captains Chair"
      belongs_to_user: "uid_0"
      category: "cat_2"
      location: "location_0"
   item_3
      name: "Science station"
      belongs_to_user: "uid_2"
      category: "cat_1"
      location: "location_0"

Categories
   cat_0
      name: "Hand held devices"
   cat_1
      name: "Stations"
   cat_2
      name: "Furniture"

Locations
   location_0
      name: "Bridge"
   location_1
      name: "Engine Room"
   location_2
      name: "Sick Bay"
   location_3
      name: "Shore leave"
一个用户可以有许多项,并且一个项属于一个用户

用户数据存储在用户集合中,documentId是用户ID。在上面的示例中,用户Kirk uid_0有两个项目,项目_0 a communicator和项目_2 a captains chair。同样,用户McCoy有一个tricorder和一个科学站Spock

一个类别可以有许多项,并且一个项属于一个类别

在本例中,我们有三个类别,通信器和Tricorder都属于cat_0手持式设备

首先,我需要列出所有项目,它们可以通过 类别和/或位置


上述结构将使您能够获得所有项目的列表。然后可以按用户、所属类别和位置对其进行筛选。

我们通常根据要执行的查询构造Firestore数据库。这些查询是什么?我将有一个用于查询所有项目的索引组件以及一个用于传递类别和位置的过滤器组件。单击某个项目会打开一个新页面,在其中我列出了更详细的信息标题、说明等。。。还有地点,分类,问什么还不清楚。查询是一个过滤器,因此注释也有点混乱。你为什么不收集4个呢。例如,items集合包含项目文档,每个文档都有一个“属于”用户字段和一个用户uid作为值?物品也是一样。有一个items集合,其中每个item文档都有一个字段“属于”\u“类别”字段和一个

类别documentID的值?地点如何配合?你能澄清这个问题吗?我假设这个项目与位置或用户有某种关联?我们通常根据我们想要执行的查询来构建Firestore数据库。这些查询是什么?我将有一个用于查询所有项目的索引组件以及一个用于传递类别和位置的过滤器组件。单击某个项目会打开一个新页面,在其中我列出了更详细的信息标题、说明等。。。还有地点,分类,问什么还不清楚。查询是一个过滤器,因此注释也有点混乱。你为什么不收集4个呢。例如,items集合包含项目文档,每个文档都有一个“属于”用户字段和一个用户uid作为值?物品也是一样。是否有一个项目集合,其中每个项目文档都有一个字段“属于”\u“类别”字段和一个类别documentID值?地点如何配合?你能澄清这个问题吗?我假设这个项目与位置或用户有某种关联?这个答案的优点在于它的设计简单。我想提到这个关于在NoSQL中建模一对多和多对一关系的系列。虽然这篇文章是为MongoDB写的,但我仍然觉得其中所解释的概念很有用。@Happy Monad,我也在考虑这篇文章。@ChristophBerger这是一个非常可靠的答案,+1对于非规范化是正常的文章-我在谈论结构时经常用到它。一些想法。我认为这里的建议是将项目保持在一个数组中。虽然Firestore支持阵列,但它们并不适合NoSQL。有一长串不使用它们的原因,但对我来说,可能90%的时间我都能想出一种更好的方法来构造和存储数据。第二件事是让数据保持浅层,这是NoSQL每次的赢家;虽然查询etc是RTDB中的常见做法和普遍做法,但Firestore的功能可以在很大程度上缓解对重复数据的需求。数组包含和复合查询非常有用,而大的查询非常有用。这改变了游戏规则,解决了许多需要以前非规范化数据的情况。所以不要过度去规范化!保持你的结构平坦,自由使用参考文档而不是重复的数据。整个讨论非常有价值,非常感谢。谢谢大家!!这个答案的优点是设计简单。我想提到这个关于在NoSQL中建模一对多和多对一关系的系列。虽然这篇文章是为MongoDB写的,但我仍然觉得其中所解释的概念很有用。@Happy Monad,我也在考虑这篇文章。@ChristophBerger这是一个非常可靠的答案,+1对于非规范化是正常的文章-我在谈论结构时经常用到它。一些想法。我认为这里的建议是将项目保持在一个数组中。虽然Firestore支持阵列,但它们并不适合NoSQL。有一长串不使用它们的原因,但对我来说,可能90%的时间我都能想出一种更好的方法来构造和存储数据。第二件事是让数据保持浅层,这是NoSQL每次的赢家;虽然查询etc是RTDB中的常见做法和普遍做法,但Firestore的功能可以在很大程度上缓解对重复数据的需求。数组包含和复合查询非常有用,而大的查询非常有用。这改变了游戏规则,解决了许多需要以前非规范化数据的情况。所以不要过度去规范化!保持你的结构平坦,自由使用参考文档而不是重复的数据。整个讨论非常有价值,非常感谢。谢谢大家!!谢谢你的详细介绍,我两种方法都试试!但是你会为引用选择什么内容类型?@ChristophBerger Strings!DocumentId只能是字符串,所以这是唯一的选项。谢谢@Jay!非常感谢,我将试一试,您的解决方案看起来非常干净,SQL非常相似。@ChristophBerger如果它最终成为解决方案,请接受它,这样它可以帮助其他人。感谢您提供的详细信息,我将尝试这两种方法!但是你会为引用选择什么内容类型?@ChristophBerger Strings!DocumentId只能是字符串,所以这是唯一的选项。谢谢@Jay!非常感谢,我将尝试一下,您的解决方案看起来非常干净,SQL非常相似。@ChristophBerger如果它最终成为解决方案,请接受它,这样它可以帮助其他人。