添加 Firebase 数据、点和正斜杠
Posted
技术标签:
【中文标题】添加 Firebase 数据、点和正斜杠【英文标题】:Adding Firebase data, dots and forward slashes 【发布时间】:2013-10-08 14:20:30 【问题描述】:我尝试使用firebase db, 我发现了非常重要的限制,这些限制在 firebase 帮助或常见问题解答中没有描述。
第一个问题是符号:点 '.'键中禁止,
即firebase 拒绝(原因不明) 下一步:
nameRef.child('Henry.Morgan@caribbean.sea').set('Pirat');
您的键“/”中的正斜杠的第二个问题, 当您尝试像这样添加密钥时
'02/10/2013': true
在firebase中你可以看到:
'02':
'10':
'2013': true
您有任何解决方法(自动)的想法吗? 可以设置一些标志,它是带有所有符号的字符串键? 当然,我可以在每次写入之前和读取之后解析/恢复数据,但是......
顺便说一句'.' '/' - firebase 的所有受限符号?
【问题讨论】:
使用github.com/cartant/firebase-key 【参考方案1】:字符限制记录在 https://www.firebase.com/docs/creating-references.html - 您不能在键名中使用“.”、“/”、“[”、“]”、“#”和“$”。没有自动转义这些字符的方法,我建议完全避免使用它们或创建自己的转义/取消转义机制。
【讨论】:
【参考方案2】:添加子 02/10/2013
在 Firebase 中创建结构的原因是正斜杠会导致创建新级别。
所以我假设您使用的行类似于:firebaseRef.child('02/10/2013').set(true)
相当于 firebaseRef.child('02').child('10').child('2013').set(true)
。
为避免在引用键名(source)中无法使用以下字符的问题,
。 (句号) $(美元符号) [(左方括号) ](右方括号) #(井号或井号) /(正斜杠)
我们可以使用 javascript 的内置编码函数之一,因为据我所知,Firebase 不 提供了一个内置方法来做到这一点。下面是一个运行过程,看看哪个对我们的目的最有效:
var forbiddenChars = '.$[]#/'; //contains the forbidden characters
escape(forbiddenChars); //results in ".%24%5B%5D%23/"
encodeURI(forbiddenChars); //results in ".%24%5B%5D%23%2F"
encodeURIComponent(forbiddenChars); //results in ".%24%5B%5D%23%2F"
显然,最有效的解决方案是encodeURIComponent
。然而,它并不能解决我们的所有问题。 .
字符仍然存在问题,如上述测试所示,并尝试encodeURIComponent
您的测试电子邮件地址。我的建议是在encodeURIComponent
之后链接一个替换函数来处理句点。
以下是您的两个示例案例的解决方案:
encodeURIComponent('Henry.Morgan@caribbean.sea').replace(/\./g, '%2E') //results in "Henry%2EMorgan%40caribbean%2Esea"
encodeURIComponent('02/10/2013'); //results in "02%2F10%2F2013"
由于两个最终结果都可以安全地作为键名插入 Firebase,唯一的另一个问题是从 Firebase 读取后进行解码,这可以通过 replace('%2E', '.')
和简单的 decodeURIComponent(...)
解决。
【讨论】:
编码似乎不能达到目的 @Philar,你是什么意思? 对不起,我很迟钝,但编码 '[' 和 ']' 仍然会导致相同的requests.exceptions.HTTPError: 400 Client Error: Bad Request
异常。最好避免在键中使用这些字符
@Philar,很有趣。我假设您正在使用 Python 请求库?您如何编码和发送请求?如果 Requests 正在撤消编码,您可能必须编码 两次。
提供的源链接错误。正确链接是:firebase.google.com/docs/database/usage/limits#data_tree【参考方案3】:
我自己也遇到过同样的问题,为此我创建了firebase-encode。
与所选答案不同,firebase-encode 仅对不安全字符 (./[]#$) 和 % 进行编码(由于编码/解码的工作原理,这是必要的)。
它会留下其他可以安全用作 firebase 密钥的特殊字符,而 encodeURIComponent
将对它们进行编码。
这里是详细的源代码:
// http://***.com/a/6969486/692528
const escapeRegExp = (str) => str.replace(/[\-\[\]\/\\\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
const chars = '.$[]#/%'.split('');
const charCodes = chars.map((c) => `%$c.charCodeAt(0).toString(16).toUpperCase()`);
const charToCode = ;
const codeToChar = ;
chars.forEach((c, i) =>
charToCode[c] = charCodes[i];
codeToChar[charCodes[i]] = c;
);
const charsRegex = new RegExp(`[$escapeRegExp(chars.join(''))]`, 'g');
const charCodesRegex = new RegExp(charCodes.join('|'), 'g');
const encode = (str) => str.replace(charsRegex, (match) => charToCode[match]);
const decode = (str) => str.replace(charCodesRegex, (match) => codeToChar[match]);
【讨论】:
太棒了!谢谢?【参考方案4】:我是为 Java 写的(因为我来这里是为了实现 Java):
public static String encodeForFirebaseKey(String s)
return s
.replace("_", "__")
.replace(".", "_P")
.replace("$", "_D")
.replace("#", "_H")
.replace("[", "_O")
.replace("]", "_C")
.replace("/", "_S")
;
public static String decodeFromFirebaseKey(String s)
int i = 0;
int ni;
String res = "";
while ((ni = s.indexOf("_", i)) != -1)
res += s.substring(i, ni);
if (ni + 1 < s.length())
char nc = s.charAt(ni + 1);
if (nc == '_')
res += '_';
else if (nc == 'P')
res += '.';
else if (nc == 'D')
res += '$';
else if (nc == 'H')
res += '#';
else if (nc == 'O')
res += '[';
else if (nc == 'C')
res += ']';
else if (nc == 'S')
res += '/';
else
// this case is due to bad encoding
i = ni + 2;
else
// this case is due to bad encoding
break;
res += s.substring(i);
return res;
【讨论】:
【参考方案5】:我对这个问题感到恼火,所以我从@sushain97 那里得到了答案(谢谢!)并构建了一个深度编码器/解码器。
https://www.npmjs.com/package/firebase-key-encode
基本用法:
var firebaseKeyEncode = require('firebase-key-encode');
firebaseKeyEncode.encode('my.bad.key');
// Output: my%2Ebad%2Ekey
深度用法:
var firebaseKeyEncode = require('firebase-key-encode');
var badTree =
"pets": [
"jimmy.choo": 15
],
"other.key": 5
firebaseKeyEncode.deepEncode(badTree);
// Output:
// "pets": [
//
// "jimmy%2Echoo": 15
// ],
// "other%2Ekey": 5
//
【讨论】:
【参考方案6】:如果您使用的是 Swift 3,这对我有用(在操场上尝试):
var str = "this.is/a#crazy[string]right$here.$[]#/"
if let strEncoded = str.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
print(strEncoded)
if let strDecoded = strEncoded.removingPercentEncoding
print(strDecoded)
【讨论】:
【参考方案7】:就我个人而言,我发现了一个简单易行的方法来解决我遇到的同样问题
我取了dateTime string
并使用replace('/','|')
转换它
结果将类似于 2017|07|24 02:39:37
而不是 2017/07/24 02:39:37
。
【讨论】:
【参考方案8】:即使这不是 OP 所要求的,
但根据我的经验,最好让.push()
创建一个ID,而不是使用这种可疑的键,
和其他东西 - 电子邮件、日期等。另存为专用字段的内容。
$id:
email: "Henry.Morgan@caribbean.sea"
附:不要试图通过将内容插入密钥来节省音量。 过早的优化是万恶之源(c)。
【讨论】:
【参考方案9】:高效的 C# 实现(适用于 Unity 和 .net)。基于@josue.0 的回答。
public static string EncodeFirebaseKey(string s)
StringBuilder sb = new StringBuilder();
foreach (char c in s)
switch (c)
case '_':
sb.Append("__");
break;
case '$':
sb.Append("_D");
break;
case '.':
sb.Append("_P");
break;
case '#':
sb.Append("_H");
break;
case '[':
sb.Append("_O");
break;
case ']':
sb.Append("_C");
break;
case '/':
sb.Append("_S");
break;
default:
sb.Append(c);
break;
return sb.ToString();
public static string DecodeFirebaseKey(string s)
StringBuilder sb = new StringBuilder();
bool underscore = false;
for (int i = 0; i < s.Length; i++)
if (underscore)
switch (s[i])
case '_':
sb.Append('_');
break;
case 'D':
sb.Append('$');
break;
case 'P':
sb.Append('.');
break;
case 'H':
sb.Append('#');
break;
case 'O':
sb.Append('[');
break;
case 'C':
sb.Append(']');
break;
case 'S':
sb.Append('/');
break;
default:
Debug.LogWarning("Bad firebase key for decoding");
break;
underscore = false;
else
switch (s[i])
case '_':
underscore = true;
break;
default:
sb.Append(s[i]);
break;
return sb.ToString();
【讨论】:
【参考方案10】:Python 实现
_escape = '&': '&&',
'$': '&36',
'#': '&35',
'[': '&91',
']': '&93',
'/': '&47',
'.': '&46'
_unescape = e: u for u, e in _escape.items()
def escape_firebase_key(text):
return text.translate(str.maketrans(_escape))
def unescape_firebase_key(text):
chunks = []
i = 0
while True:
a = text[i:].find('&')
if a == -1:
return ''.join(chunks + [text[i:]])
else:
if text[i+a:i+a+2] == '&&':
chunks.append('&')
i += a+2
else:
s = text[i+a:i+a+3]
if s in _unescape:
chunks.append(text[i:i+a])
chunks.append(_unescape[s])
i += a+3
else:
raise RuntimeError('Cannot unescape')
还有一些测试用例:
test_pairs = [('&hello.', '&&hello&46'),
('&&&', '&&&&&&'),
('some@email.com', 'some@email&46com'),
('#$[]/.', '&35&36&91&93&47&46')]
for u, e in test_pairs:
assert escape_firebase_key(u) == e, f"escaped 'u' is 'e', but was 'escape_firebase_key(u)'"""
assert unescape_firebase_key(e) == u, f"unescaped 'e' is 'u', but was 'unescape_firebase_key(e)'"
try:
unescape_firebase_key('&error')
assert False, 'Must have raised an exception here'
except RuntimeError as ex:
assert str(ex) == 'Cannot unescape'
【讨论】:
以上是关于添加 Firebase 数据、点和正斜杠的主要内容,如果未能解决你的问题,请参考以下文章
Oracle 中的 JDBC 瘦连接字符串同时使用冒号和正斜杠