【问题标题】:Firebase Cloud Firestore Many to Many RelationshipsFirebase Cloud Firestore 多对多关系
【发布时间】:2018-03-19 10:27:23
【问题描述】:

如何以多对多关系从 Firebase Cloud Firestore 构造和查询数据?

我有公司和承包商。一个承包商可以为多个公司工作,一个公司可以有多个承包商。这是一个简单的多对多关系。我希望能够回答有关公司和承包商的问题:

给定一家公司,他们是当前的承包商。 给定承包商他们为什么公司工作。 在 Cloud Firestore 中构建数据的正确方法是什么?

【问题讨论】:

  • 嗯,它是document-model database,所以我认为你不应该以关系的方式来思考它。无论如何,我认为你可以只为给定的公司收集一组承包商,反之亦然(所以是的,你会有某种“重复”)。我不认为您可以像在关系数据库中那样拥有“规范化”模型。
  • 我看到了几种方法。公司可以包含承包商的子集合,或者反过来,承包商可以包含公司的子集合。这意味着一些承包商或公司是重复的。也许改用空文档并使用 id 在其他集合中查找。什么是最好的取决于您的典型查询。尝试一下并根据您的需要调整数据库。
  • 或者反过来你尝试创建一个新的集合来存储承包商和公司之间的关系,因为如果我们查询主集合的子集合,我们不会得到相关的子集合的数据.
  • Firestore 文档说:“作为 NoSQL 数据库,它在描述数据对象之间关系的方式上与它们不同。” cloud.google.com/firestore/docs。这是什么意思?

标签: firebase google-cloud-firestore


【解决方案1】:

您可以拥有带有地图字段的 Contractors 项目,该字段将键作为公司键,并且值可以是 true 或者时间戳以帮助订购。 以及具有以承包商键为键和一些值的地图字段的公司。 https://firebase.google.com/docs/firestore/solutions/arrays 中提到了这种方法,当您尝试一起过滤和排序时...

Contractors
  companies
    idCompany1: timestamp
    idCompany2: timestamp
    idCompany3: timestamp

Companies
  contractors
    idContractor1: timestamp
    idContractor2: timestamp

在这种情况下,您可以像该公司的承包商或该承包商的公司一样进行任何查询。 像这样:

fireStore.collection("Companies").whereField("contractors." + idContractor, isGreaterThan: 0).order(by: "contractors." + idContractor, descending: true)

是的,您必须在任何任务中更新这两个地方

希望这会有所帮助!

【讨论】:

  • 我与客户/用户的结构完全相同。我唯一要添加的是 Firestore 安全规则可能是这样的:allow read: if resource.data.contractors[request.auth.uid] > 0;假设 idContractor1 是 uid。然后只有承包商才能看到允许的公司。
  • 为什么要将时间戳作为值?
  • @NateUni 您的问题是开放式的,取决于您的要求。一个用例是识别何时添加它以进行排序,请记住这是一种双向/多对多的设计模式,预计它是多余的。但在我看来,最好使用一个字节数较少的值字段,例如布尔值/空值。 Read more
  • @NateUni 我也忘了提到一个用例,用于将集合的写入限制提高到500*n,当您的写入超过每秒 500 次时,您可以通过分片时间戳来使用它,您可以在Firestore Guides了解更多关于那里的信息
  • 请记住,这种方法至少有几个limitations。 Firestore 中的文档大小不能超过 1Mb。此外,每个文档实际上最多可以有 20,000 个字段,这意味着每个公司只能存储有限数量的承包商,反之亦然。
【解决方案2】:

正如 André Lima 在他的回答中所解释的,您可以使用数组来表示关系。但我不认为这两个集合都需要一个用于映射的数组字段。只有一个集合需要有一个关系数组的字段。

companies: {
  contractors: ['contractor_id_1', 'contractor_id_2', 'contractor_id_2']
}

查询时,可以使用array-contains operator根据数组值进行过滤。

示例查询(网络):

companiesRef.where("contractors", "array-contains", "contractor_id_1")

您还可以根据需要使用inarray-contains-any 运算符。

【讨论】:

  • 您将如何获取特定公司的所有承包商文件(通过公司 ID)?本质上类似于:`contractorsRef.where("companies", "array-contains", "company_id_1"),我认为您需要在每个承包商文档中包含一系列公司?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-16
  • 2017-05-22
  • 1970-01-01
  • 2018-03-16
  • 1970-01-01
  • 2018-07-08
相关资源
最近更新 更多