Shahzain ali
Shahzain ali

Reputation: 1725

How to only get child keys in Firebase

Firebase database

I want to display only children of location i.e Sindh and Punjab (not their children). Is it possible, and if so how can I do it?

Upvotes: 6

Views: 21557

Answers (8)

Cisco G
Cisco G

Reputation: 69

I know this question was asked a while ago and for android, but I was looking for a solution to this and came upon this question. I couldn't use the answers provided, so here is the solution I found. This will only get the children and nothing else.

This is in javascript, but you can use whichever method is the alternative in java to make a request from a REST endpoint.

const databaseURL = "https://example.firebaseio.com" // replace value with yours
const endpoint = "location"
const user = firebase.auth().currentUser
user.getIdToken()
  .then(token => {
    return fetch(`${databaseURL}/${endpoint}.json?auth=${token}&shallow=true`)
  })
  .then(response => {
    return response.json()
  })
  .then(json => {
    console.log({json}) // contains only the children
  })
  .catch(error => {
    console.log(error.message)
  })

The important bit here is the &shallow=true otherwise you get all the data in the children.

Using curl this would be

curl 'https://example.firebaseio.com/location.json?auth=INSERT_TOKEN&shallow=true'

This assumes location is a child of the root.

More details can be had by looking at the docs

Before calling this, you have to make sure you have the currentUser available in firebase.

Also, I would heed the warnings mentioned here about proper firebase realtime database structure. However, if you are already in this spot, then this can help.

Upvotes: 1

DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("location");

final ArrayList<String> statesArrayList= new ArrayList<>();

databaseReference.addChildEventListener(new ChildEventListener() {

    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String s) {
        statesArrayList.add(dataSnapshot.getKey());
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String s) {

    }

    @Override
    void onChildRemoved(DataSnapshot dataSnapshot) {

    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String s) {

    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
});

Upvotes: 4

Alex Mamo
Alex Mamo

Reputation: 1

Firebase can as quickly look up a node at level 1 as it can at level 32. Depth is not a factor that affects speed on a technical level but years of experience with Firebase has shown that deeply nested data often goes hand in hand with performance problems. As an example, i recomand you reading the offical documentation, Best practices for data structure in Firebase and Structuring your Firebase Data correctly for a Complex App.

If you don't want to change your actual database structure and assuming that location node is a direct child of your Firebase root, please see the code below:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference locationRef = rootRef.child("location");
ValueEventListener eventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for(DataSnapshot ds : dataSnapshot.getChildren()) {
            String key = ds.getKey();
            Log.d("TAG", key);
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
};
locationRef.addListenerForSingleValueEvent(eventListener);

Your output will be:

punjab
sindh

Upvotes: 1

Jatin Gupta
Jatin Gupta

Reputation: 48

Though nesting data is not recommended in NoSQL databases like Firebase, to get the name of child nodes your code will look like this

DatabaseReference mainRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference locationref = mainRef.child("location");
final ArrayList<String> locationNames = new ArrayList<>();
locationref.addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String s) {
        locationNames.add(dataSnapshot.getKey());
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String s) {

    }

    @Override
    void onChildRemoved(DataSnapshot dataSnapshot) {

    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String s) {

    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
});

You can now use locationNames to do what you want.

Upvotes: 1

UmarZaii
UmarZaii

Reputation: 1351

Avoid Nesting Data

Because the Firebase Realtime Database allows nesting data up to 32 levels deep, you might be tempted to think that this should be the default structure. However, when you fetch data at a location in your database, you also retrieve all of its child nodes. In addition, when you grant someone read or write access at a node in your database, you also grant them access to all data under that node. Therefore, in practice, it's best to keep your data structure as flat as possible.

Below is a structure of yours on how to implement flat database as well as how to retrieve the location key.

{
  "location": {
    "punjab": {
      "lahore": true,
      "multan": true
    },
    "sindh": {
      "karachi": true
    }
  },

  "place": {
    "lahore": {
      "location": "punjab",
      "details": {
        "0": "model",
        "1": "steel town"
      }
    },
    "multan": {
      "location": "punjab",
      "contacts": {
        "0": "myarea"
      }
    },
    "karachi": {
      "location": "sindh",
      "contacts": {
        "0": "hadeed",
        "1": "Steel town"
      }
    }
  }
}

Below is the code that you can use to retrieve the location key.

private DatabaseReference mDatabase;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();
mLocation = mDatabase.child("location");
mPlace = mDatabase.child("place");

ValueEventListener placeListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // Get Post object and use the values to update the UI
        Place place = dataSnapshot.getValue(Place.class);
        String location = place.location;
        System.out.println(location);
    }
};
mPlace.addValueEventListener(placeListener);

For more information on Firebase:

Upvotes: 9

Shahadat Hossain Shaki
Shahadat Hossain Shaki

Reputation: 806

This is how u can get child names

HashMap<String, Object> allData = (HashMap<String, Object>) dataSnapshot.getValue();
String[] yourChildArray = allData.keySet().toArray(new String[0]);

Upvotes: -1

Yes, you can

ValueEventListener getValueListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
    // Get data from firebase
    Log.d("The name of child that you need:", dataSnapshot.getKey());
    // ...
}

};

databaseReference.addValueEventListener(getValueListener );

Read more: https://firebase.google.com/docs/database/android/read-and-write#listen_for_value_events

Upvotes: 1

nhaarman
nhaarman

Reputation: 100468

From Best practices for data structure in the docs:

Avoid nesting data

Because the Firebase Realtime Database allows nesting data up to 32 levels deep, you might be tempted to think that this should be the default structure. However, when you fetch data at a location in your database, you also retrieve all of its child nodes. In addition, when you grant someone read or write access at a node in your database, you also grant them access to all data under that node. Therefore, in practice, it's best to keep your data structure as flat as possible.

That is how Firebase works: If you get an item, you get its children as well. If you don't want this, you should restructure the database.

Upvotes: 17

Related Questions