134

I'm trying to create an application where I can get/set data in specific users accounts and I was tempted by Firebase.

The problem I'm having is that I don't know how to target specific users data when my structure looks like this:

My data structure described by the text below.

online-b-cards
  - users
    - InnROTBVv6FznK81k3m
       - email: "hello@hello"
       - main:  "Hello world this is a text"
       - name:  "Alex"
       - phone: 12912912

I've looked around and I can't really find anything on how to access individual data let alone when they're given some random hash as their ID.

How would I go about grabbing individual user information based of their name? If there is a better way of doing this please tell me!

BSMP
  • 4,596
  • 8
  • 33
  • 44
Richard Bamford
  • 1,835
  • 3
  • 15
  • 19
  • try this : http://stackoverflow.com/questions/32886546/how-to-get-all-child-list-from-firebase-android/36600791#36600791 – ugali soft Apr 17 '16 at 20:54

8 Answers8

159

Previously, Firebase required you to generate your own indexes or download all data at a location to find and retrieve elements that matched some child attribute (for example, all users with name === "Alex").

In October 2014, Firebase rolled out new querying functionality via the orderByChild() method, that enables you to do this type of query quickly and efficiently. See the updated answer below.


When writing data to Firebase, you have a few different options which will reflect different use cases. At a high level, Firebase is a tree-structured NoSQL data store, and provides a few simple primitives for managing lists of data:

  1. Write to Firebase with a unique, known key:

    ref.child('users').child('123').set({ "first_name": "rob", "age": 28 })
    
  2. Append to lists with an auto-generated key that will automatically sort by time written:

    ref.child('users').push({ "first_name": "rob", "age": 28 })
    
  3. Listen for changes in data by its unique, known path:

    ref.child('users').child('123').on('value', function(snapshot) { ... })
    
  4. Filter or order data in a list by key or attribute value:

    // Get the last 10 users, ordered by key
    ref.child('users').orderByKey().limitToLast(10).on('child_added', ...)
    
    // Get all users whose age is >= 25
    ref.child('users').orderByChild('age').startAt(25).on('child_added', ...)
    

With the addition of orderByChild(), you no longer need to create your own index for queries on child attributes! For example, to retrieve all users with the name "Alex":

ref.child('users').orderByChild('name').equalTo('Alex').on('child_added',  ...)

Engineer at Firebase here. When writing data into Firebase, you have a few different options which will reflect different application use cases. Since Firebase is a NoSQL data store, you will need to either store your data objects with unique keys so that you can directly access that item or load all data at a particular location and loop through each item to find the node you're looking for. See Writing Data and Managing Lists for more information.

When you write data in Firebase, you can either set data using a unique, defined path (i.e. a/b/c), or push data into a list, which will generate a unique id (i.e. a/b/<unique-id>) and allow you to sort and query the items in that list by time. The unique id that you're seeing above is generated by calling push to append an item to the list at online-b-cards/users.

Rather than using push here, I would recommend using set, and storing the data for each user using a unique key, such as the user's email address. Then you can access the user's data directly by navigating to online-b-cards/users/<email> via the Firebase JS SDK. For example:

function escapeEmailAddress(email) {
  if (!email) return false

  // Replace '.' (not allowed in a Firebase key) with ',' (not allowed in an email address)
  email = email.toLowerCase();
  email = email.replace(/\./g, ',');
  return email;
}

var usersRef = new Firebase('https://online-b-cards.firebaseio.com/users');
var myUser = usersRef.child(escapeEmailAddress('hello@hello.com')) 
myUser.set({ email: 'hello@hello.com', name: 'Alex', phone: 12912912 });

Note that since Firebase does not permit certain characters in references (see Creating References), we remove the . and replace it with a , in the code above.

Gastón Saillén
  • 12,319
  • 5
  • 67
  • 77
Rob DiMarco
  • 13,226
  • 1
  • 43
  • 55
  • What i dont get is when u do a query u get an object that has the id as a property, in this case the escaped email, the value being the object you set. Of course if your reading a list u dont know the id so... how u supposed to read the data? – Sam Mar 31 '14 at 07:42
  • @Sam I don't fully understand your question, but if file a separate question with some sample code and explain your use case, I'm happy to help out. – Rob DiMarco Mar 31 '14 at 14:37
  • 2
    @RobDiMarco Do you have an answer for the question posted below by Stephen? – Charles Han Aug 26 '14 at 20:59
  • 2
    Hey @RobDiMarco. While your suggestion to use email-addresses as the basis for the id is still valid, it might be worth expanding your answer to point to the new `orderByChild` feature. Given that this answer shows up quite often as a relevant/related answer, people are bound to look at it and should be aware of the new query features. – Frank van Puffelen Nov 24 '14 at 14:21
  • 1
    @FrankvanPuffelen Great idea - thanks for the note. I'll get this updated today. – Rob DiMarco Nov 24 '14 at 19:08
  • I am using angular fire ,please tell me the same applicable methods – bharath muppa Apr 20 '15 at 18:04
  • your answer is describing the concept clearly but, still am not getting how can i achieve the filtering of list. – Mahesh Agrawal Nov 24 '16 at 09:46
  • Since you work at Firebase, I've a couple questions, why is the database API so restrictive ? What features are in the work ? Where can one request new features ? I'd suggest you extend your documentation with an advanced section to describe how it works under the hood. Not every one using Firebase is a database illiterate and not understanding things under the hood makes it harder to reason about that black box, at least it makes it harder to understand why it is the way it is. – Ced Aug 21 '17 at 22:05
  • 1
    @Ced Unfortunately, I can't comment on what is in the works. I promise that we're hard at work (that's always been true), but can't give specifics. The Database API is indeed restrictive in some ways, and we do this deliberately to only expose methods for which we can guarantee certain levels of performance. This is why we don't expose a method to run an operation over an entire list, for example. Fair point on the docs for advanced users. When in doubt, try our Google Group for detailed conversations: https://groups.google.com/forum/#!forum/firebase-talk The team is very active here! – Rob DiMarco Aug 21 '17 at 23:54
  • 1
    @RobDiMarco That is wonderful to hear. I saw Firebase functions yesterday, and was hyped the whole day because I thought Firebase is a game changer and about to revolutionize the back-end. Seriously, I could teach someone who has never coded in his life to maintain a backend on Firebase. That's quite amazing, and quite scary. Cheers – Ced Aug 22 '17 at 00:00
  • @RobDiMarco Is there any way to retrieve all users with name **containing** a string? So for example, if I search with "ald", I get users named "Don**ald**","Ron**ald**o", "Ger**ald**" etc. – Ehtesham Hasan Feb 19 '18 at 13:31
  • @EhteshamHasan That's not possible, as far as I know. – Rob DiMarco Mar 09 '18 at 22:09
6

You can grab the details by the following code.

FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("users");
myRef.orderByChild("name").equalTo("Alex").addListenerForSingleValueEvent(new ValueEventListener() {           
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {

                    for (DataSnapshot childDataSnapshot : dataSnapshot.getChildren()) {
                        Log.d(TAG, "PARENT: "+ childDataSnapshot.getKey());
                        Log.d(TAG,""+ childDataSnapshot.child("name").getValue()); 
                    }
Nabajyoti Das
  • 454
  • 7
  • 10
4

I think the best approach is to define the ids of the users based o the auth object provided by the Firebase. When I create my users, I do:

FirebaseRef.child('users').child(id).set(userData);

This id comes from:

var ref = new Firebase(FIREBASE);
var auth = $firebaseAuth(ref);
auth.$authWithOAuthPopup("facebook", {scope: permissions}).then(function(authData) {
    var userData = {}; //something that also comes from authData
    Auth.register(authData.uid, userData);
}, function(error) {
    alert(error);
});

The Firebase auth services will always ensure a unique id among all their providers to be set at uid. This way always you will have the auth.uid and can easily access the desired user to update it, like:

FirebaseRef.child('users').child(id).child('name').set('Jon Snow');
diegopso
  • 457
  • 3
  • 11
2

This was a paraphrasing of a post that helped me when trying to access the auto-generated unique id. Access Firebase unique ids within ng-repeat using angularFire implicit sync

Thanks, bennlich (source):

Firebase behaves like a normal javascript object. Perhaps the example below can get you on the right track.

<div ng-repeat="(name, user) in users">
    <a href="" ng-href="#/{{name}}">{{user.main}}</a>
</div>

Edit: Not 100% sure of your desired outcome, but here's a bit more that might spark an 'aha' moment. Click on the key that you are trying to access right in your Firebase dashboard. From there you can use something like:

var ref = new Firebase("https://online-b-cards.firebaseio.com/users/<userId>/name);
    ref.once('value', function(snapshot) {
        $scope.variable= snapshot.val();
});
Community
  • 1
  • 1
AnthonyC
  • 31
  • 3
  • Hello Anthony, thank you for information reguarding the REST structure (?) and it definitely did strick an 'aha'. Looking back at this post it clear to me now that I had structured my data in a bit of an awkward way, thanks for the tips and i'll keep it in mind for my next firebase-based project! – Richard Bamford Jan 05 '16 at 23:54
2

This is how to access the auto generated unique keys in Firebase: data structure: - OnlineBcards - UniqueKey

database.ref().on("value", function(snapshot) {
      // storing the snapshot.val() in a variable for convenience
      var sv = snapshot.val();
      console.log("sv " + sv); //returns [obj obj]

      // Getting an array of each key in the snapshot object
      var svArr = Object.keys(sv);
      console.log("svArr " + svArr); // [key1, key2, ..., keyn]
      // Console.log name of first key
      console.log(svArr[0].name);
}, function(errorObject) {
  console.log("Errors handled: " + errorObject.code);
});
Juan Reyes
  • 21
  • 4
1

The simplest way is to stop using the .push(){}

function which will generate that random key. But instead use the .update(){} function where you may specify the name of the child instead of having the random key.

Miah Thompson
  • 239
  • 2
  • 12
1

Retrieving data:

In your database, you are using a random id that is generated using the push(), therefore if you want to retrieve the data then do the following:

Using Firebase in Android App:

DatabaseReference ref=FirebaseDatabase.getInstance().getReference().child("users");
ref.addListenerForSingleValueEvent(new ValueEventListener() {           
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {

                for (DataSnapshot datas : dataSnapshot.getChildren()) {
                    String name=datas.child("name").getValue().toString();
                }
             }

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

Using Firebase in Javascript:

  firebase.database().ref().child("users").on('value', function (snapshot) {
   snapshot.forEach(function(childSnapshot) {
    var name=childSnapshot.val().name;
  });
});

Here you have the snapshot(location of the data) at users then you loop inside all the random ids and retrieve the names.


Retrieving data for a Specific User:

Now if you want to retrieve information for a specific user only, then you need to add a query:

Using Firebase in Android App:

DatabaseReference ref=FirebaseDatabase.getInstance().getReference().child("users");
Query queries=ref.orderByChild("name").equalTo("Alex");
queries.addListenerForSingleValueEvent(new ValueEventListener() {...}

Using Firebase with Javascript

firebase.database().ref().child("users").orderByChild("name").equalTo("Alex").on('value', function (snapshot) {
   snapshot.forEach(function(childSnapshot) {
      var name=childSnapshot.val().name;
   });
});

Using orderByChild("name").equalTo("Alex") is like saying where name="Alex" so it will retrieve the data related to Alex.


Best Way:

The best thing is to use Firebase Authentication, thus generating a unique id for each user and using it instead of a random id push(), this way you do not have to loop through all the users since you have the id and can easily access it.

First, the user needs to be signed in then you can retrieve the unique id and attach a listener to retrieve the other data of that user:

Using Firebase with Android:

DatabaseReference ref = FirebaseDatabase.getInstance().getReference("users");
String uid = FirebaseAuthentication.getInstance().getCurrentUser().getUid();

ref.child(uid).addListenerForSingleValueEvent(new ValueEventListener() {
          @Override
         public void onDataChange(DataSnapshot dataSnapshot) { 
           String name=dataSnapshot.child("name").getValue().toString(); 
   }
         @Override
       public void onCancelled(DatabaseError databaseError) {
      }
 });

Using Firebase with Javascript:

    var user = firebase.auth().currentUser;
    var uid=user.uid;

    firebase.database().ref().child("users").child(uid).on('value', function (snapshot) {
     var name=snapshot.val().name;
   });
 
Community
  • 1
  • 1
Peter Haddad
  • 78,874
  • 25
  • 140
  • 134
0

The simplest and better way to add unique Id to ur database according to authenticated user is this:

private FirebaseAuth auth;

String UId=auth.getCurrentUser().getUid();

FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("Users");

User user = new User(name,email,phone,address,dob,bloodgroup);

myRef.child(UId).setValue(user);

The UId will be a unique Id for a specific authenticated email/user

  • 3
    That doesn't address the question. The question was how to get and set data in specific user accounts. Your code creates a user account and is actually not valid as your cannot .setValue(user) because *user* is not a valid parameter. – Jay Mar 31 '17 at 19:35