【问题标题】:Firestore - proper NoSQL structure for user-specific dataFirestore - 适合用户特定数据的 NoSQL 结构
【发布时间】:2021-10-19 21:34:27
【问题描述】:

我正在使用 Firestore 开发一个应用程序。我使用 Firebase 身份验证来管理用户。 问题是我的应用程序中的大部分数据都是特定于用户的。这意味着用户只能访问自己的数据。

我已经研究过 Firestore 安全规则,所以我知道如何处理安全部分。

但是,我想知道如何正确地为用户特定的数据建模。我要添加的第一条数据是 categories,它(目前)有 2 个属性:nametype

经过一番研究,我发现最好创建一个名为 categories 的集合,然后为每个用户创建一个文档,每个文档都以用户 ID (UID) 命名。

但是,在这样一个特定于用户的文档中,我想添加我的类别。我想出的一种方法如下面的截图所示:

所以,用更通用的方式来描述这种方法:

  1. 每种数据类型的新集合(例如categories
  2. 在集合内,为每个用户使用 UID 命名的单独文档
  3. 在每个用户特定的文档中,包含对象数据的映射(例如,category_1 映射字段为 name = groceriestype = expense

然而,这里让我担心的是,我需要以某种方式发明这些地图的名称,例如 category_1category_2 等...我感觉这个模型有问题,但我强大的 SQL 背景并没有不让我这么想????

您是否知道这个模型是否是一个好的模型,或者它以后会产生什么问题?也许您可以建议一种更好的方法来在 Firestore 数据库中对用户特定的数据进行建模?

【问题讨论】:

    标签: firebase google-cloud-firestore


    【解决方案1】:

    单个用户可以拥有多少个类别有任何限制吗?如果没有,那么最好为类别创建一个集合以避免点击1 MB max document size。如果有限制并且您决定使用地图,我建议创建一个地图字段categories 并将它们作为它的子项,如下所示,因此如果您在文档中添加任何其他字段,它将更多 分类:

    {
      categories: {
        category_1: {
          name: "",
          type: ""
        },
        category_2: {
          name: "",
          type: ""
        }
      }
    }
    

    但是,如果每个类别将来获得更多数据并且您需要对类别进行一些查询,那么创建子集合也可能是更好的选择。

    users -> {userId} -> categories -> {categoryId}
    (col)     (doc)        (col)          (doc)
    

    由于类别位于子集合中,因此您无需在每个类别文档中添加 userId 字段。但是,您也可以创建 2 个不同的根集合,即 - 用户和类别:

    users -> {userId}
    (col)      (doc)
    
    categories -> {categoryId}
    (col)           (doc)
    

    在这种情况下,您必须存储 userId 字段以在这些类别的所有者之间进行过滤。

    @Alex Mamo 在这篇文章中完美解释了使用根级集合和子集合之间的区别,如果您需要深入解释:What are the benefits of using a root collection in Firestore vs. a subcollection?


    这两种情况下的安全规则会有所不同。如果您使用子集合,那么您可以像这样从通配符中读取用户 UID:

    match /users/{userId}/categories/{categoryId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
    

    但是,如果您使用根级别的集合,每个类别的文档 ID 通常不会有用户的 UID,但 UID 将作为字段存储在文档中。在这种情况下,您必须从所请求的文档中读取userId

    match /categories/{categoryId} {
      allow read, write: if request.auth != null && request.auth.uid == resource.data.userId;
    }
    

    让我担心的是我需要以某种方式发明这些地图的名称

    NoSQL 数据库没有架构。您可以根据需要动态添加任何键。只需将每个文档视为 JSON 对象即可。

    const newKey = "category_123"
    const newValue = {name: "newCatName", type: "expense"}
    
    const userDoc = firebase.firestore().collection("users").doc("userId")
    userDoc.update({
      [`categories.${newKey}`]: newValue
    })
    

    此更新操作将使用提供的值在“类别”映射中创建一个新子项。

    【讨论】:

    • 感谢您的回答。它让我明白了让我担心的事情:) 我想我会选择users 顶级集合和categories 子集合,即用户 -> {userId} -> 类别 -> {categoryId}。类别在我的应用程序中的用户之间不是全局/共享的,它们将始终在用户上下文中进行处理。我认为这将使查询和安全性更容易。
    猜你喜欢
    • 2017-03-14
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多