Добавление данных Firebase, точек и косых черт

Я пытаюсь использовать firebase db, Я нашел очень важные ограничения, которые не описаны в справке firebase или часто задаваемых вопросах.

Первая проблема заключается в том, что символ: точка '.' запрещено в ключах,

то есть. firebase отклонение (по неизвестной причине) next:

        nameRef.child('[email protected]').set('Pirat');

Вторая проблема с косой чертой в ваших клавишах '/', когда вы пытаетесь добавить такой ключ

        {'02/10/2013': true}

В firebase вы можете увидеть:

         '02': {
             '10': {
                 '2013': true
             }
         }       

У вас есть идеи, как его решить (автоматически)? Может быть установлен некоторый флаг, что это строковый ключ со всеми символами? Конечно, я могу анализировать/восстанавливать данные каждый раз перед записью и после чтения, но...

Кстати, '.' '/' - все ограниченные символы для firebase?

Ответ 1

Причина, по которой добавление дочернего элемента 02/10/2013 создает структуру в Firebase, заключается в том, что в результате слэша в результате создается новый уровень.

Итак, строка, которую я предполагаю, вы используете нечто похожее: firebaseRef.child('02/10/2013').set(true) эквивалентно firebaseRef.child('02').child('10').child('2013').set(true).

Чтобы избежать проблем с невозможностью использования следующих символов в именах ссылочных ключей (источник),

  • . (период)
  • $(знак доллара)
  • [(левая квадратная скобка)
  • ] (правая квадратная скобка)
  • # (знак хеша или фунта)
  • /(косая черта)

мы можем использовать один из 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('[email protected]').replace(/\./g, '%2E') //results in "Henry%2EMorgan%40caribbean%2Esea"
encodeURIComponent('02/10/2013'); //results in "02%2F10%2F2013"

Поскольку оба окончательных результата безопасны для вставки в Firebase в качестве имени ключа, единственная проблема заключается в расшифровке после чтения из Firebase, которая может быть решена с помощью replace('%2E', '.') и простого decodeURIComponent(...).

Ответ 2

Я сам столкнулся с той же проблемой, и для этой цели я создал firebase-encode.

В отличие от выбранного ответа firebase-encode кодирует только небезопасные символы (./[]#$) и % (необходимо из-за того, как работает кодирование/декодирование). Он оставляет другие специальные символы, которые безопасны для использования в качестве ключа firebase, в то время как encodeURIComponent будет их кодировать.

Здесь исходный код для деталей:

// 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

Ограничения символов документируются на https://www.firebase.com/docs/creating-references.html - вы не можете использовать '.', '/', '[', ']', '#' и '$' в именах ключей. Автоматического способа избежать этих символов нет, я бы рекомендовал вообще избегать их использования или создать собственный механизм экранирования/отмены.

Ответ 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

Если вы используете 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)
    }
}

Ответ 6

Меня это раздражало, поэтому я взял ответ от @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
// }

Ответ 7

Лично я нашел простой и легкий взлом для этой же проблемы, с которой я столкнулся

Я взял dateTime string и преобразовал ее, используя replace('/','|')

результат будет примерно таким: 2017|07|24 02:39:37 вместо 2017/07/24 02:39:37.

Ответ 8

Я не вижу "автоматического" встроенного в кодер FireBase для ключей.

Вот решение Java.

Я построил это, упрощенную версию ответа josue.0, но я думаю, что это лучший код, поскольку его версия может вызвать проблемы. Многие люди будут использовать _P или _D в своем коде, поэтому он должен быть более сложным и маловероятным.

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;