Android 如何在Firebase中正确地反规范化数据

Android 如何在Firebase中正确地反规范化数据,android,firebase,denormalization,Android,Firebase,Denormalization,我对NoSQL和非规范化非常陌生。但是,我希望允许我的应用程序中的注册操作定义为: 如果已使用用户名,则不允许用户使用该用户名 如果某个电话号码已被占用,则不允许用户使用该号码 允许新用户与服务器“同步”其电话号码联系人,以确定当前用户,并检索其各自的uid 鉴于快速需要检查用户注册时是否已经存在用户名/电话号码,以及如果新用户的联系人电话号码链接到应用程序中已经存在的用户,则需要进行搜索和比较,我的架构概述如下: { "presentUsersByPhoneNumber" : {

我对NoSQL和非规范化非常陌生。但是,我希望允许我的应用程序中的
注册
操作定义为:

  • 如果已使用用户名,则不允许用户使用该用户名
  • 如果某个电话号码已被占用,则不允许用户使用该号码
  • 允许新用户与服务器“同步”其电话号码联系人,以确定当前用户,并检索其各自的uid
  • 鉴于快速需要检查用户注册时是否已经存在用户名/电话号码,以及如果新用户的联系人电话号码链接到应用程序中已经存在的用户,则需要进行搜索和比较,我的架构概述如下:

    {
      "presentUsersByPhoneNumber" : {
        "1614#######" : {
          "uid" : "fdb17f3a-7b7d-4aa5-9a0b-b9fb33c349de"
        },
        "1614#######" : {
          "uid" : "99e4989b-a046-4c5f-9478-5ebd8bdc3ded"
        },
        "1614#######" : {
          "uid" : "1783917f-00e4-47a0-b2cd-987bdf185129"
        },
        "1614#######" : {
          "uid" : "a96da7b1-7c4e-44bc-b82e-fc75bed52bcd"
        }
      },
      "presentUsersByUsername" : {
        "ak" : {
          "uid" : "a96da7b1-7c4e-44bc-b82e-fc75bed52bcd"
        },
        "ak2" : {
          "uid" : "99e4989b-a046-4c5f-9478-5ebd8bdc3ded"
        },
        "ak3" : {
          "uid" : "1783917f-00e4-47a0-b2cd-987bdf185129"
        },
        "kja" : {
          "uid" : "fdb17f3a-7b7d-4aa5-9a0b-b9fb33c349de"
        }
      },
      "users" : {
        "1783917f-00e4-47a0-b2cd-987bdf185129" : {
          "phoneNumber" : "614#######",
          "username" : "ak3"
        },
        "99e4989b-a046-4c5f-9478-5ebd8bdc3ded" : {
          "phoneNumber" : "1614#######",
          "username" : "ak2"
        },
        "a96da7b1-7c4e-44bc-b82e-fc75bed52bcd" : {
          "phoneNumber" : "1614#######",
          "username" : "ak1"
        },
        "fdb17f3a-7b7d-4aa5-9a0b-b9fb33c349de" : {
          "phoneNumber" : "1614#######",
          "username" : "kja"
        }
      }
    }
    

    这种方法在非规范化行为中是否过于公平?

    在NoSQL中,您应该为应用程序访问数据的方式建模。更多信息请阅读本文

    因此,如果您需要一种有效的方法来检查电话号码或用户名是否已被占用,那么存储这些号码或用户名的映射是有意义的。我可能会做的唯一不同的事情是将它们存储为简单类型:

    "phoneNumberToUid" : {
        "1614#######" : "fdb17f3a-7b7d-4aa5-9a0b-b9fb33c349de"
        "1614#######" : "99e4989b-a046-4c5f-9478-5ebd8bdc3ded"
    },
    "usernameToUid" : {
        "ak" : "a96da7b1-7c4e-44bc-b82e-fc75bed52bcd"
        "ak2" : "99e4989b-a046-4c5f-9478-5ebd8bdc3ded"
    }
    
    我在示例数据中注意到的一点是,在
    presentUsersByUsername
    中有一个键
    ak
    ,但在
    users
    中没有与该
    名称对应的子项。这通常是因为您的代码中途中止,或者是因为您在开发过程中的某个时候犯了错误

    您可以通过以下方式预防这些问题:

  • 使用多位置更新,以便将所有写入作为单个命令发送到Firebase

    ref.update({
      '/users/a96da7b1-7c4e-44bc-b82e-fc75bed52bcd/username': 'ak1',
      '/usernameToUid/ak': null,
      '/usernameToUid/ak1': 'a96da7b1-7c4e-44bc-b82e-fc75bed52bcd'
    });
    
    此更新是将用户名称从
    ak
    更改为
    ak1
    的最安全的方法,它将删除旧映射并添加新映射

  • 使用验证规则确保每个名称都有一个用户

    "usernameToUid": {
      "$username": {
        ".validate": "newData.parent().parent().child(newData.va()).child('username').val() == $username"
      }
    }