Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving data from Firebase Realtime Database in Android

I'm new to Firebase and NoSQL. I have an Android Demo, with a City Autocomplete Text Field in which I want to populate the cities I have from my Firebase DB, while typing.

{   "cities":{
        "Guayaquil":true,
        "Gualaceo":true,
        "Quito":true,
        "Quevedo":true,
        "Cuenca":true,
        "Loja":true,
        "Ibarra":true,
        "Manta":true
    }
}

This is what I have so far.

How can I retrieve from the DB cities that start with a letter (input from keyboard)? If I start typing "G", I want to receive "Guayaquil" and "Gualaceo".

If I use orderByValue always returns an empty snapshot.

If I use orderByKey return the whole list.

    Query citiesQuery = databaseRef.child("cities").startAt(input).orderByValue();
    citiesQuery.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            List<String> cities = new ArrayList<String>();
            for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
                cities.add(postSnapshot.getValue().toString());
            }

Note: If you can recommend a better data structure, you're welcome.

like image 260
Erick Medina Avatar asked Sep 27 '16 02:09

Erick Medina


2 Answers

@NicholasChen has identified the problem. But here's the way you'd implement using the 3.x SDK:

DatabaseReference cities = databaseRef.child("cities")
Query citiesQuery = cities.orderByKey().startAt(input).endAt(input+"\uf8ff");
citiesQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        List<String> cities = new ArrayList<String>();
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            cities.add(postSnapshot.getValue().toString());
        }

By starting at the user input and ending at the last string that starts with the user input, you get all matching items

For relatively short lists of items Ryan's approach will also work fine. But the above Firebase query will filter server-side.

Update

I just ran this code:

    DatabaseReference databaseRef = FirebaseDatabase.getInstance().getReference("39714936");

    String input = "G";

    DatabaseReference cities = databaseRef.child("cities");
    Query citiesQuery = cities.orderByKey().startAt(input).endAt(input + "\uf8ff");
    citiesQuery.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            List<String> cities = new ArrayList<String>();

            for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
                cities.add(postSnapshot.getValue().toString());
            }
            System.out.println(cities);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

And it printed:

true

true

So clearly matches two cities.

Feel free to test against my database: https://stackoverflow.firebaseio.com/39714936

like image 173
Frank van Puffelen Avatar answered Sep 20 '22 15:09

Frank van Puffelen


Try something like this to iterate over the children in the cities snapshot and add all the cities to an ArrayList of Strings.

ArrayList<String> cityList = new ArrayList<>();

databaseRef.child("cities").addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        cityList.clear();
        for (DataSnapshot data : dataSnapshot.getChildren()){
            cityList.add(data.getKey);
        }

    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w(TAG, "getUser:onCancelled", databaseError.toException());
        // ...
    }
});

Editing this paragraph for clarity:

This will get all your cities read into the program memory so you can use that data to display the cities to the user. If the city list changes, so will the data the user sees. If the user is not online, this will not work. This puts a real time, online only listener on the database.

The logic in my mind is something like:

  1. Set a value listener on the text box.
  2. When user types, make a view display all the items in the array list that start with the same substring that was typed.
  3. Handle arrayIndex errors of course.

Hopefully this will get you on the right track. I am sure there are other ways you could implement it but this is what I would personally do. If you need help with the code to display the correct cities, start a chat with me and I can brainstorm with you.

like image 35
Ryan Avatar answered Sep 21 '22 15:09

Ryan