2015-08-09 35 views
14

我的用例是保存用户的信息。通过他们的电子邮件好的方法来替换Firebase中的无效字符?

Error: Invalid key [email protected] (cannot contain .$[]#)

所以,很显然,我不能索引用户信息:当我尝试保存数据使用用户的电子邮件地址作为重点火力,火力地堡引发以下错误。取代.的最佳做法是什么?

我已经成功地将.更改为-,但由于某些电子邮件地址中有一些电子邮件地址为-,因此不会切断它。

目前,我使用

var cleanEmail = email.replace('.','`'); 

,但也有可能会成为下与此行的冲突。

回答

12

在电子邮件地址,请用逗号,更换点.。这种模式是最佳实践。

逗号,在电子邮件地址中允许的字符,但它在火力地堡键允许的。对称地,点.电子邮件地址中允许的字符,但它是而不是允许在Firebase密钥中使用。所以直接替代会解决你的问题。您可以索引电子邮件地址,而无需循环任何内容。

您还有其他问题。在您的代码:

var cleanEmail = email.replace('.',','); 

只会替换第一个点.但电子邮件地址可以有多个点。要替换所有点实例,应该使用正则表达式代替。具体如下:

var cleanEmail = email.replace(/\./g, ','); 
6

我们已经处理了这个问题很多次,表面上看起来像使用电子邮件作为一个关键是一个简单的解决方案,它导致了很多其他问题:必须清理/解析电子邮件,以便它实际上可以使用。如果电子邮件更改会怎样?

我们发现改变数据存储方式是一条更好的路径。假设你只需要存储一个东西,即用户名。

[email protected]: "John Smith" 

其改为

randomly_generated_node_name 
    email: "[email protected]" 
    first: "John" 
    last: "Smith" 

的randomly_generated_node_name是火力地堡可以通过childByAutoId产生,或真不直接绑定到数据的任何类型的参考的字符串。

这提供了很大的灵活性:你现在可以改变人的姓氏 - 比方说他们结婚了。或更改他们的电子邮件您可以添加可用于排序的'index'子元素0,1,2等。可以查询任何儿童数据的数据。所有这些都是因为random_generated_node_name是对节点内变量子数据的静态引用。

它还允许您在未改变现有数据的情况下在未来扩展数据。添加地址,喜爱的食物,排序等

编辑索引:用于电子邮件火力地堡查询在ObjC:

//references all of the users ordered by email 
FQuery *allUsers = [myUsersRef queryOrderedByChild:@"email"]; 

//ref the user with this email 
FQuery *thisSpecificUser = [allUsers queryEqualToValue:@“[email protected]”]; 

//load the user with this email 
[thisSpecificUser observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) { 
    //do something with this user 
}]; 
+0

谢谢杰伊。我应该指定更好的。我保存的数据就像你在主/用​​户数据库中建议的那样。作为密钥的电子邮件用于索引查找。所以我的index/users/email/'[email protected]'被设置为实际的用户ID。也许我会考虑更多的思考如何通过一个arraylike格式索引 – irth

+0

是的 - 这只是导致各种编码问题。最好不要使用实际的电子邮件(或任何可能会改变的数据)作为关键。您可能只想为每个用户节点添加一个索引子节点:index:“0”,index:“1”等等。这样你就可以获得类似数组的行为,而不必实际使用数组(这通常是一个坏主意),并且可以通过名称,电子邮件或索引来查询特定用户。 – Jay

+0

啊,也许我还没有看到它,但是我不需要遍历所有的用户,直到找到我正在查找的电子邮件。我在索引中使用电子邮件作为关键字,以便直接查找并理解属性更改时所需的额外代码。我困惑吗? – irth

2

我能想到的两种主要方式来解决这个问题:

  1. 编码/解码功能

由于有限的字符集的允许的Firebase密钥,解决方案是将密钥转换为有效格式(编码)。然后有一个反函数(解码)将编码密钥转换回原始密钥。

一般的编码/解码函数可能会将原始密钥转换为字节,然后将它们转换为十六进制表示。但密钥的大小可能是一个问题。

比方说,你要使用电子邮件的用户存储的关键:

# path: /users/{email} is User; 
/users/[email protected]: { 
    name: "Alice", 
    email: "[email protected]" 
} 

上面的例子并不因为路径点的工作。所以我们使用编码功能将密钥转换为有效的格式。 [email protected]十六进制是616c69636540656d61696c2e636f6d,则:只要它们共享相同的hex功能

# path: /users/{hex(email)} is User; 
/users/616c69636540656d61696c2e636f6d: { 
    name: "Alice", 
    email: "[email protected]" 
} 

任何客户端可以访问该资源。

编辑:Base64也可用于编码/解码密钥。可能比十六进制更有效,但有许多不同的实现。如果客户不共享完全相同的实现,那么他们将无法正常工作。

也可以使用专门的功能(例如只处理电子邮件)。但一定要处理所有的边缘情况。

  • 编码具有原始键功能存储
  • 做的一种方式的关键的转化是一个容易得多。因此,不是使用解码功能,而是将原始密钥存储在数据库中。

    很好编码这种情况下的功能是SHA-256算法。这是在很多平台上实现的常用算法。碰撞的机会非常渺茫。

    前面的例子与SHA-256变成这样:

    # path: /users/{sha256(email)} is User; 
    /users/55bf4952e2308638427d0c28891b31b8cd3a88d1610b81f0a605da25fd9c351a: { 
        name: "Alice", 
        email: "[email protected]" 
    } 
    

    与原来的钥匙(电子邮件)可以找到这个条目,因为编码功能是已知的任何客户端(已知) 。而且,即使密钥变大,SHA-256的大小也将始终如一,因此,保证是有效的Firebase密钥。

    +0

    这可能是OP中提出的特殊用例(即电子邮件点)的一般解决方案。我很好奇Firebase团队是否认可这种模式为“最佳实践”? @FrankvanPuffelen – Mowzer

    +0

    @Mowzer我现在在其他地方使用这个相同的想法。我会把答案改写成更一般的。希望了解来自Firebase团队的潜在问题。但到目前为止,这对我来说非常有用。 –

    相关问题