androidfirebasefirebase-realtime-database

Firebase Realtime Database Query Issue


I have a database of 800+ items and I want to filter them by rarity. With "single" rarity (e.g only "legendary" rarity) I can easily do this, but the problem appears when trying to combine two rarities (e.g "event & basic" rarity).

This is the method I use:

 private void loadFirebaseData(String rarity1, String rarity2) {

    DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Outfits");
    reference.keepSynced(true);

    Query query = reference.orderByChild("rarity").startAt(rarity1).endAt(rarity2);
    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

            arrayCosmetics = new ArrayList<>();

            for (DataSnapshot data : dataSnapshot.getChildren()) {
                Cosmetics cosmetics = data.getValue(Cosmetics.class);
                arrayCosmetics.add(cosmetics);
            }

            cosmeticsAdapter = new CosmeticsAdapter(getActivity(), arrayCosmetics);
            cosmeticsAdapter.setHasStableIds(true);

            recyclerView.setVisibility(View.VISIBLE);
            recyclerView.setAdapter(cosmeticsAdapter);

            Collections.shuffle(arrayCosmetics, new Random(3));

            rootView.findViewById(R.id.progressBar).setVisibility(View.GONE);

        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
        }
    });
}

And calling it like: loadFirebaseData("basic", "event");

So the issue is that it loads me all the rarities from alphabetically "b" all the way to "e" (e.g "basic", "classic", "common", "elite", "epic") and obviously I want only "basic" and "event"

The database is structured like this:

"01" : {
"available" : "X",
"created" : "20191023",
"id" : 1,
"image" : "x",
"info" : "x",
"marketable" : true,
"name" : "xx",
"rarity" : "x",
"slot" : "xx" }

"02" : {
"available" : "x",
"created" : "20191023",
"id" : 1,
"image" : "x",
"info" : "x",
"marketable" : true,
"name" : "x",
"rarity" : "x",
"slot" : "x" }

Firebase rules:

 "Outfits": {
  ".indexOn": ["rarity"]
}

It is possible to achieve what I want without loading the whole database in one big ArrayList<>()?

If I have the whole ArrayList<>() I can do something like this:

private void rarityFilter(String rarity1, String rarity2) {
    
    ArrayList<Cosmetics> newListCosmetics = new ArrayList<>();

    for (Cosmetics cosmetics : arrayCosmetics) {
        String name = cosmetics.getRarity().toLowerCase();
        if (name.contains(rarity1) || name.contains(rarity2))
            newListCosmetics.add(cosmetics);
    }
    cosmeticsAdapter.setFilter(newListCosmetics);
}

But isn't it bad for performance to load the whole ArrayList<>()?


Solution

  • It sounds like you're trying to load nodes whose rarity property either have a value of event or a value of basic. The Firebase Realtime Database doesn't support such OR queries, nor are there a lot of good work-arounds to implement them.

    The most common workarounds are:

    Also see: