user3358423
user3358423

Reputation: 85

Firebase Query in Functions not returning as expected

I'm trying to do something fairly simple but I'm having a lot of trouble getting the expected behavior. In a firebase function triggered by an external HTTP call, I'm trying to pull an object from Firebase Database based on the value I get in the HTTP call.

The strange part is that essentially the same code works in my web app (using angular) but it does not work in the Functions (based on Node).

Here is the database structure:

ROOT
/users
    /-L1toTQ_nLwyy2jhuz1h
        /athlete
            /name
            /id
            /country
    /-L1twwvmpAvBI80uHpFc
        /athlete
            /name
            /id
            /country

On my web-app built with Javascript (Angular), the following function returns a snapshot as I expect. I'm searching within each user (without knowing the unique ID (-L1toTQ_nLwyy2jhuz1h). Instead, I'm searching for the id nested under users/{unique}/athlete/... and that works as I expect.

This Works

var fire = firebase.database();
var externalID = 12345;
var users = fire.ref('users');
var query = users.orderByChild('athlete/id').equalTo(externalID);

query.once('value', function(snap){
  var k = Object.keys(snap.val())[0]; //gets the key of the first result
  var user = snap.val(); // sets user = full returned object from firebase
  console.log(user[k]); // logs below
});

This is what gets logged to the console for user[k], as expected:

{
"athlete": {
    "country": "United States",
    "name": "Jack",
    "id": 12345,
    }
}

I used that code as my basis for writing my cloud Function, but I cannot get a similar result. Instead, the snap.val() = null and snap.key = 'users'. That means I get an error when I try to run var k = Object.keys(snap.val())[0]

This Doesn't Work

var admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
var db = admin.database();

exports.incomingTest = functions.https.onRequest((request, response) => {

    const externalId = 12345;

    const users = db.ref('users');
    const query =  users.orderByChild('athlete/id').equalTo(externalId);

    query.once('value').then(snap => {
        console.log(snap.val()); // logs null
        console.log(snap.key);  // logs 'users'


    }).catch(reason =>{
        console.log(reason);
     });
    response.send(200)
});

I've looked around as much as I can about this, some places say that you can't query multiple levels deep but clearly from the web-application I can... so I don't see why it doesn't work from the cloud functions. Also, I found one article saying Firebase added the ability to query multiple levels deep.

I also got an error previously saying I was searching on a non-indexed variable, so I added it to my rules and I no longer get that error.

{
 "rules": {
         ".read": "auth != null",
         ".write": "auth != null",
         "users": {
                 ".indexOn": "athlete/id"
                  }
          }
 }

Last, I'm not getting an error response from the query.once() functions (note the .catch()). But I'm actually getting the snap returned successfully, but it is null.

Upvotes: 0

Views: 615

Answers (1)

Doug Stevenson
Doug Stevenson

Reputation: 317352

I'm not entirely certain this is will fix your particular problem, but I can tell you you're not writing your HTTPS type function correctly. HTTPS functions are terminated after they send a response. In your case, you're sending a response technically before the database query completes (because on() is async, it returns immediately).

Try writing it like this to ensure your database query completes before the response is sent:

query.once('value').then(snap => {
    console.log(snap.val()); // logs null
    console.log(snap.key);  // logs 'users'
    response.send('ok')  // note: send does not take a status code
}).catch(reason =>{
    console.log(reason);
    response.status(500).send('not ok')
});

Also note that I've corrected your use of the response.

Upvotes: 1

Related Questions