0

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" : "Wanderer Crate",
"created" : "20191023T021358Z",
"id" : 11010006,
"image" : "https://prod-live-front.playbattlegrounds.com/images/item_176/11010006.png",
"info" : "Drop Chance: 5.00%",
"marketable" : true,
"name" : "Dirty Tank Top (White)",
"rarity" : "common",
"slot" : "torso" }

"02" : {
"available" : "Wanderer Crate",
"created" : "20191023T021358Z",
"id" : 11010014,
"image" : "https://prod-live-front.playbattlegrounds.com/images/item_176/11010014.png",
"info" : "Drop Chance: 5.00%",
"marketable" : true,
"name" : "Tank Top (Charcoal)",
"rarity" : "common",
"slot" : "torso" }

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<>()?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Moisoni Ioan
  • 1,370
  • 1
  • 13
  • 24

1 Answers1

0

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:

  • Add a property for each combination that you want to allow, e.g. "rarity_event_or_basic": true and then filter for that. It's not great though, as it requires lots of properties, and becomes hard to index.
  • Perform a separate query for each value, and merge the results in your application code. This is quite efficient as far performance goes, as Firebase can execute them in parallel. But the code typically is a bit convoluted, and if you want to combine it with a limit filter, you likely end up retrieving more data than needed.
  • If the values are lexicographically close to each other, you can use a range condition. E.g. ref.orderByChild("rarity").startAt("basic").endAt("event").

Also see:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807