Kevin192291
Kevin192291

Reputation: 2097

Reading from firebase inside a cloud function

Can anyone help me determine why firebase isn't returning the value from a cloud function? It seems like reading from on database change is simple, but when doing a http on request, firebase functions just hangs and finally times out.

exports.getTotalPrice = functions.https.onRequest((req, res) => {
  var data = "";
   req.on('data', function(chunk){ data += chunk})
   req.on('end', function(){
       req.rawBody = data;
       req.jsonBody = JSON.parse(data);
       res.end(next(req.jsonBody));
   })
});
function next(json) {
  var total = 0;
  for(var i = 0; i < json.products.length; i++) {
    //Get product by UPC
    console.log(order.products[i].upc);
    codeRef.orderByKey()
      .equalTo(order.products[i].upc)
        .once('value', function(snap) {
          console.log(snap.val()); // returns `null`
          return (snap.val()[0].msrp);
    })
    //Multiply the price of the product by the quantity
    console.log(order.products[i].quantity);

    //add it to the total price
  }
}

Upvotes: 1

Views: 1062

Answers (2)

Kato
Kato

Reputation: 40582

You are running several asynchronous functions but you aren't informing your function when they are done. The function needs to return a promise to succeed here.

Note also that if the database call fails, it's going to do so silently here. So you should capture errors and report those as well.

Note also that you're storing your distributed JSON data as arrays, which you probably shouldn't.

Note also that you're using .orderByKey().equalTo() when you could just be using .child(upc).

So what you've essentially got here is a mess. You need to spend some time in the guide and samples--you're going to spend a lot of time thrashing like this if you don't.

For a starting point, reduce your code set to the simplest use case runs as expected:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.testDbOp = functions.https.onRequest((req, res) => {
  return admin.database()
     .ref('/foo')
     .once('value')
     .then(snap => res.send(JSON.stringify(snap.val()))
     .catch(e => console.error(e));
});

Once you have that working, if you want to fetch several values asynchronously, you can do that with Promise.all(), something like this:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.testDbOp = functions.https.onRequest((req, res) => {
  const promises = [];
  const output = {};
  const jsonData = {....};
  jsonData.products.forEach(product => {
     promises.push( codeRef.child(product.upc).once('value')
       .then(snap => output[product.upc] = snap.val()[0].msrp);
  });
  return Promise.all(promises).then(() => res.send(JSON.stringify(output));
});

Upvotes: 2

Josh Pittman
Josh Pittman

Reputation: 7324

It doesn't seem like you are calling the database at all. I only see functions.https.onRequest() which is a http trigger https://firebase.google.com/docs/functions/http-events.

If you wanted to call the database it would have to be something more like functions.database.ref('/').onWrite(event => {}) so that it references the database https://firebase.google.com/docs/functions/database-events.

onWrite refers to any kind of change at that point in the database, not just writing to the database. https://firebase.google.com/docs/functions/database-events#reading_the_previous_value

Upvotes: 1

Related Questions