问题
I try to use firebase db, I found very important restrictions, which are not described in firebase help or FAQ.
First problem is that symbol: dot '.' prohibited in keys,
i.e. firebase reject (with unknown reason) next:
nameRef.child('Henry.Morgan@caribbean.sea').set('Pirat');
Second problem with forward slashes in your keys '/', when you try to add key like this
{'02/10/2013': true}
In firebase you can see:
'02': {
'10': {
'2013': true
}
}
Have you got any ideas how to solve it (automatically)? May be set some flag that it is string key with all symbols? Of course, I can parse/restore data every time before write and after read, but...
By the way '.' '/' - all restricted symbols for firebase ?
回答1:
The reason that adding a child 02/10/2013
creates a structure in Firebase is because the forward slashes are resulting in the creation of a new level.
So the line I assume you are using something similar to: firebaseRef.child('02/10/2013').set(true)
is equivalent to firebaseRef.child('02').child('10').child('2013').set(true)
.
To avoid the problems of not being able to use the following characters in reference key names (source),
- . (period)
- $ (dollar sign)
- [ (left square bracket)
- ] (right square bracket)
- # (hash or pound sign)
- / (forward slash)
we can use one of JavaScript's built in encoding functions since as far as I can tell, Firebase does not provide a built in method to do so. Here's a run-through to see which is the most effective for our purposes:
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"
Evidently, the most effective solution is encodeURIComponent
. However, it doesn't solve all our problems. The .
character still poses a problem as shown by the above test and trying to encodeURIComponent
your test e-mail address. My suggestion would be to chain a replace function after the encodeURIComponent
to deal with the periods.
Here's what the solution would look like for your two example cases:
encodeURIComponent('Henry.Morgan@caribbean.sea').replace(/\./g, '%2E') //results in "Henry%2EMorgan%40caribbean%2Esea"
encodeURIComponent('02/10/2013'); //results in "02%2F10%2F2013"
Since both the final results are safe for insertion into a Firebase as a key name, the only other concern is decoding after reading from a Firebase which can be solved with replace('%2E', '.')
and a simple decodeURIComponent(...)
.
回答2:
I faced the same problem myself, and I have created firebase-encode for this purpose.
Unlike the chosen answer, firebase-encode encodes only unsafe characters (./[]#$) and % (necessary due to how encoding/decoding works).
It leaves other special characters that are safe to be used as firebase key while encodeURIComponent
will encode them.
Here's the source code for details:
// http://stackoverflow.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]);
回答3:
I wrote this for Java (since I came here expecting a java implementation):
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;
}
回答4:
Character limitations are documented at https://www.firebase.com/docs/creating-references.html - you cannot use '.', '/', '[', ']', '#', and '$' in key names. There is no automatic way of escaping these characters, I'd recommend avoiding their use altogether or creating your own escaping/unescaping mechanism.
回答5:
If you're using Swift 3, this works for me (try it in a playground):
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)
}
}
回答6:
I got annoyed with this problem so I took the answer from @sushain97 (thanks!) and built a deep encoder/decoder.
https://www.npmjs.com/package/firebase-key-encode
Basic usage:
var firebaseKeyEncode = require('firebase-key-encode');
firebaseKeyEncode.encode('my.bad.key');
// Output: my%2Ebad%2Ekey
Deep Usage:
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
// }
回答7:
I don't see an "automatic" built in FireBase encoder for keys.
Here is a Java solution.
I built this, a simplified version of josue.0's answer, but I think it is better code since his version could cause problems. A lot of people will use _P or _D in their code, so it needs to be more complex and unlikely.
public static String encodeForFirebaseKey (String s) {
s = s.replace(".", "_P%ë5nN*")
.replace("$", "_D%5nNë*")
.replace("#", "_H%ë5Nn*")
.replace("[", "_Oë5n%N*")
.replace("]", "_5nN*C%ë")
.replace("/", "*_S%ë5nN")
;
return s;
}
public static String decodeFromFirebaseKey(String s) {
s = s.replace("_P%ë5nN*", ".")
.replace("_D%5nNë*", "$")
.replace("_H%ë5Nn*", "#")
.replace("_Oë5n%N*", "[")
.replace("_5nN*C%ë", "]")
.replace("*_S%ë5nN", "/");
return s;
回答8:
Personally, I found a simple and easy hack for this same problem I encountered
I took the dateTime string
and convert it using replace('/','|')
the result will be something like this 2017|07|24 02:39:37
instead of 2017/07/24 02:39:37
.
来源:https://stackoverflow.com/questions/19132867/adding-firebase-data-dots-and-forward-slashes