1

I have a data like this:

"customers": {
    "aHh4OTQ2NTlAa2xvYXAuY29t": {
        "customerId": "xxx",
        "name": "yyy",
        "subscription": "zzz"
    }
}

I need to retrive a customer by customerId. The parent key is just B64 encoded mail address due to path limitations. Usually I am querying data by this email address, but for a few occasions I know only customerId. I've tried this:

getCustomersRef()
   .orderByChild('customerId')
   .equalTo(customerId)
   .limitToFirst(1)
   .once('child_added', cb);

This works nicely in case the customer really exists. In opposite case the callback is never called.

I tried value event which works, but that gives me whole tree starting with encoded email address so I cannot reach the actual data inside. Or can I?

I have found this answer Test if a data exist in Firebase, but that again assumes that you I know all path elements.

getCustomersRef().once('value', (snapshot) => {
    snapshot.hasChild(`customerId/${customerId}`);
});

What else I can do here ?

Update

I think I found solution, but it doesn't feel right.

let found = null;
snapshot.forEach((childSnapshot) => {
    found = childSnapshot.val();
});
return found;
Community
  • 1
  • 1
FredyC
  • 3,999
  • 4
  • 30
  • 38
  • Possible duplicate of [How to query firebase for property with specific value inside all children](http://stackoverflow.com/questions/25272919/how-to-query-firebase-for-property-with-specific-value-inside-all-children) – huysentruitw Nov 27 '15 at 11:18
  • 1
    Also [this](http://stackoverflow.com/a/14965065/1300910) answer might help you – huysentruitw Nov 27 '15 at 11:19
  • Can you clarify the question? It states you want to 'retrieve a child record when parent key is unknown'. That's what a firebase query does - it 'looks' through a set of nodes to see if any of them has a child matching the data you specify - the parent node doesn't need to be specified, only the node that is the parent of the nodes that contain the child you are looking for. – Jay Nov 28 '15 at 14:52

1 Answers1

1

old; misunderstood the question :

If you know the "endcodedB64Email", this is the way.:

var endcodedB64Email = B64_encoded_mail_address;

firebase.database().ref(`customers/${endcodedB64Email}`).once("value").then(snapshot => {
       // this is getting your customerId/uid. Remember to set your rules up for your database for security! Check out tutorials on YouTube/Firebase's channel.
       var uid = snapshot.val().customerId;
       console.log(uid) // would return 'xxx' from looking at your database

// you want to check with '.hasChild()'? If you type in e.g. 'snapshot.hasChild(`customerId`)' then this would return true, because 'customerId' exists in your database if I am not wrong ...
});

UPDATE (correction) :

We have to know at least one key. So if you under some circumstances only know the customer-uid-key, then I would do it like this.:

// this is the customer-uid-key that is know. 
var uid = firebase.auth().currentUser.uid; // this fetches the user-id, referring to the current user logged in with the firebase-login-function
// this is the "B64EmailKey" that we will find if there is a match in the firebase-database
var B64EmailUserKey = undefined;

// "take a picture" of alle the values under the key "customers" in the Firebase database-JSON-object
firebase.database().ref("customers").once("value").then(snapshot => {
     // this counter-variable is used to know when the last key in the "customers"-object is passed
     var i = 0;
     // run a loop on all values under "customers". "B64EmailKey" is a parameter. This parameter stores data; in this case the value for the current "snapshot"-value getting caught
     snapshot.forEach(B64EmailKey => {
          // increase the counter by 1 every time a new key is run
          i++;
          // this variable defines the value (an object in this case)
          var B64EmailKey_value = B64EmailKey.val();
          // if there is a match for "customerId" under any of the "B64EmailKey"-keys, then we have found the corresponding correct email linked to that uid
          if (B64EmailKey_value.customerId === uid) {
               // save the "B64EmailKey"-value/key and quit the function
               B64EmailUserKey = B64EmailKey_value.customerId;

               return B64UserKeyAction(B64EmailUserKey)
          }

          // if no linked "B64EmailUserKey" was found to the "uid"
          if (i === Object.keys(snapshot).length) {
               // the last key (B64EmailKey) under "customers" was returned. e.g. no "B64EmailUserKey" linkage to the "uid" was found
               return console.log("Could not find an email linked to your account.")
          }
     });
});

 // run your corresponding actions here
 function B64UserKeyAction (emailEncrypted) {
      return console.log(`The email-key for user: ${auth.currentUser.uid} is ${emailEncrypted}`)
 }

I recommend putting this in a function or class, so you can easily call it up and reuse the code in an organized way.

I also want to add that the rules for your firebase must be defined to make everything secure. And if sensitive data must be calculated (e.g. price), then do this on server-side of Firebase! Use Cloud Functions. This is new for Firebase 2017.

ravo10
  • 895
  • 9
  • 18
  • It's little bit old question, I don't remember how I solved it, but as I said above "but for a few occasions I know only customerId". Your solution is expecting that endcodedB64Email is known, which isn't. – FredyC May 21 '17 at 20:58
  • Hello. Sorry about that. I have now updated the answer for how to get the right 'endcodedB64Email' if you only know the 'customerId'. Tell me if this was what you though of. – ravo10 May 22 '17 at 12:09
  • 1
    Thanks, but this must have awful memory footprint essentially loading all customers (till correct one is found). I guess that best way, in the end, would be to have a separate lookup map with customeri->email. – FredyC May 23 '17 at 11:52
  • 1
    Yes, definitely uses more memory. Firebase encourages to denormalize data allot in the database. To use a separate lookup like you mentioned `customerId => email` would be the best! Simple code like e.g. `firebase.database().ref("users/" + auth.currentUser.uid).once("value").then(snap => {var email = snap.val().email});` – ravo10 May 23 '17 at 18:05
  • I do think it is OK to do it in this way if you have to. If I am not wrong, Firebase is built to do this kind of data-handling. Your dataplan might go up though. This example encourages people to do this if needed. [firebase.docs](https://firebase.google.com/docs/database/web/lists-of-data#listen_for_value_events) – ravo10 May 23 '17 at 19:17