1
String key = databaseReference.child("Photo").push().getKey();
// ...
databaseReference.child("Photo").child(key).setValue(post);

As far as I know, Firebase creates a statistically guaranteed unique ID here and it also has an order. I checked it and indeed it does have an order. Likes this, it always inserts new elements at the end of the data structure. For example like this:

-MqWU0En0OezPglE6SfL: true
-MqWUFoFqhIaT6fSk-DT: true
-MrmJaNZ8lbcOFPodTBO: true

becomes:

-MqWU0En0OezPglE6SfL: true
-MqWUFoFqhIaT6fSk-DT: true
-MrmJaNZ8lbcOFPodTBO: true
-Mrq162Eba8KHgc_B0lh: true (New Element was inserted here at the end!)

I need to have it the other way around. I need to have it inserted at the beginning. Is there a way to do that? Maybe something like push().getKeyAtBeginning()? I couldn't find anything.


If not, what do you suggest?

In the child, photo are thousands of photos. I know that you can insert a child element negativetimestamp to each photo that has the value -1 * currentMillis, and then just use orderByChild(negativetimestamp). But I don't think this would be a good idea since there are thousands or even ten-thousands of photos that Firebase would have to order then.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
mathematics-and-caffeine
  • 1,664
  • 2
  • 15
  • 19

2 Answers2

2

Unfortunately, there is no way you can use something like this:

push().getKeyAtBeginning()

You cannot add a node to a specific index. Besides that, there is also no way you can change the order of the nodes in the Firebase Console. All the nodes are by default ordered by key.

If you need to order your elements by specific criteria, then your idea is the way to go ahead with. I have also answered a similar question:

If there are thousands or even ten-thousands of photos, then you should consider getting them in smaller chunks. This approach is called pagination.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Do you mean pagination already inside the storage of the data in Firebase? Or just pagination for getting the items like in the link you mentioned. Because in the latter case I still have the problem of having the wrong order. However, I found a way that works fine for me and posted it as an answer. I'm not sure if this is good style because it surely isn't the way Firebase intended it to be. So could you maybe tell me if there are any issues that might come with time with the method I used there? – mathematics-and-caffeine Dec 26 '21 at 12:54
  • Pagination just to get the items, as in the link I mentioned. Without seeing the code, I cannot say why you got the wrong order. But if have added a timestamp correctly, then it will work for sure, either ascending or descending if you invert the long number. – Alex Mamo Dec 27 '21 at 08:33
  • No, what I meant is, I would get the correct order, but Firebase would still have to sort ten-thousands elements everytime. It happens on the server side and I only get let's say 20 items per page, but Firebase would still have to order all ten-thousand items, doesn't it? Because otherwise how can it know the order it has to return the items? – mathematics-and-caffeine Dec 27 '21 at 08:55
  • 1
    In that case, you should consider using [Cloud Firestore](https://firebase.google.com/docs/firestore), where that problem doesn't exist. [In Firestore the query performance depends on the number of documents you request and not on the number of documents you search.](https://stackoverflow.com/questions/69161968/flutter-firestore-logical-or-best-practice) – Alex Mamo Dec 27 '21 at 08:58
2

The old code in this answer contained bugs! Because of that, I thoroughly coded it new.


Firebase uses a timestamp to ensure the chronological order of the generated keys. I wrote a method to lexicographically invert a key (in a bijective way), so all order relations between two keys still exist, but in reverse. So if key1 > key2, then after that key1 < key2.


New code:

import java.util.HashMap;
import java.util.Map;

public class InvertiereKey {

    /**
     * all allowed chars for a firebase key in a lexicographical order (except SPACE)
     */
    private static Map<Integer, String> hashtable;

    private static void initHash() {
        if (hashtable == null) {
            hashtable = new HashMap<>();

            hashtable.put(0, "!");
            hashtable.put(1, "\"");
            hashtable.put(2, "%");
            hashtable.put(3, "'");
            hashtable.put(4, "(");
            hashtable.put(5, ")");
            hashtable.put(6, "*");
            hashtable.put(7, "+");
            hashtable.put(8, ",");
            hashtable.put(9, "-");
            //hashtable.put(10, "/"); // This does NOT work because child("a/b") means child("a").child("b")
            hashtable.put(10, "0");
            hashtable.put(11, "1");
            hashtable.put(12, "2");
            hashtable.put(13, "3");
            hashtable.put(14, "4");
            hashtable.put(15, "5");
            hashtable.put(16, "6");
            hashtable.put(17, "7");
            hashtable.put(18, "8");
            hashtable.put(19, "9");
            hashtable.put(20, ":");
            hashtable.put(21, ";");
            hashtable.put(22, "<");
            hashtable.put(23, "=");
            hashtable.put(24, ">");
            hashtable.put(25, "?");
            hashtable.put(26, "@");
            hashtable.put(27, "A");
            hashtable.put(28, "B");
            hashtable.put(29, "C");
            hashtable.put(30, "D");
            hashtable.put(31, "E");
            hashtable.put(32, "F");
            hashtable.put(33, "G");
            hashtable.put(34, "H");
            hashtable.put(35, "I");
            hashtable.put(36, "J");
            hashtable.put(37, "K");
            hashtable.put(38, "L");
            hashtable.put(39, "M");
            hashtable.put(40, "N");
            hashtable.put(41, "O");
            hashtable.put(42, "P");
            hashtable.put(43, "Q");
            hashtable.put(44, "R");
            hashtable.put(45, "S");
            hashtable.put(46, "T");
            hashtable.put(47, "U");
            hashtable.put(48, "V");
            hashtable.put(49, "W");
            hashtable.put(50, "X");
            hashtable.put(51, "Y");
            hashtable.put(52, "Z");
            hashtable.put(53, "\\");
            hashtable.put(54, "^");
            hashtable.put(55, "_");
            hashtable.put(56, "`");
            hashtable.put(57, "a");
            hashtable.put(58, "b");
            hashtable.put(59, "c");
            hashtable.put(60, "d");
            hashtable.put(61, "e");
            hashtable.put(62, "f");
            hashtable.put(63, "g");
            hashtable.put(64, "h");
            hashtable.put(65, "i");
            hashtable.put(66, "j");
            hashtable.put(67, "k");
            hashtable.put(68, "l");
            hashtable.put(69, "m");
            hashtable.put(70, "n");
            hashtable.put(71, "o");
            hashtable.put(72, "p");
            hashtable.put(73, "q");
            hashtable.put(74, "r");
            hashtable.put(75, "s");
            hashtable.put(76, "t");
            hashtable.put(77, "u");
            hashtable.put(78, "v");
            hashtable.put(79, "w");
            hashtable.put(80, "x");
            hashtable.put(81, "y");
            hashtable.put(82, "z");
            hashtable.put(83, "{");
            hashtable.put(84, "|");
            hashtable.put(85, "}");
            hashtable.put(86, "~");
        }
    }

    
    /**
     * um andere einfuege reihenfolge von push().getKey() bei firebase zu haben
     * Also am anfang wird eingefuegt dann, nicht ans ende
     *
     * @param key
     * @return
     */
    public static String invertiereKey(String key) {
        initHash();

        String invertiert = "";

        // get char array
        char[] charArray = key.toCharArray();

        // iterate over it and invert every char lexicographically
        int i = 0;
        while (i < charArray.length) {
            char charTemp = charArray[i];

            // get numerical value
            int numerical = getNumericalFromChar(charTemp);

            // invert the numerical representation
            // there are 88 chars
            // 0 --> first char, 87 --> last char
            int numericalNeu = 87 - numerical;

            // get char again
            String newChar = hashtable.get(numericalNeu);

            // add to inverted string
            invertiert += newChar;

            i++;
        }

        return invertiert;
    }

    private static int getNumericalFromChar(char c) {
        String s = Character.toString(c);

        for (Map.Entry<Integer, String> entry : hashtable.entrySet()) {
            if (s.equals(entry.getValue())) {
                return entry.getKey();
            }
        }

        return 0; // never called with proper input (ie. a firebase key generated from pushKey())
    }
}

Usage:

String key = reference.pushKey();
String invertedKey = InvertiereKey.invertiereKey(key);
reference.child(invertedKey).setValue(...);
mathematics-and-caffeine
  • 1,664
  • 2
  • 15
  • 19