Annemieke
Annemieke

Reputation: 63

Firebase function - query firestore

Im trying to retrieve some data from firestore within a cloud function, but get nothing back. The same query on the client-side gives me the correct results. It's probably something small but I don't see the issue. What am I doing wrong?

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
db.settings({ timestampsInSnapshots: true });

exports.myFunction = functions.https.onCall((data, context) => {
  const info = getInfo();
  //do some stuff with the info
  return info;
}

function getInfo() {
  const query = db
    .collection('info')
    .where('table_nr', '==', 1)
    .where('number', '<=', 25)
    .orderBy('number', 'desc')
    .limit(1);

  const info = query.get().then(snapshot => {
    snapshot.forEach(doc => {
      return doc.data();
    })
  })
  return info;
}

When I make a call to this function I get: "data: null"

let info = functions.httpsCallable('myFunction')

info().then(res => { console.log(res) })

I tried a lot of different options, like when I change the last part to:

const info = query.get().then(snapshot => {
  snapshot.docs;
})

I get an array with 1 object. So I'm sure there is a document in the query with data. The console.log gives me:

{data: Array(1)}
data: Array(1)
0: {_ref: {…}, _fieldsProto: {…}, _serializer: {…}, _validator: {…}, 
_readTime: {…}, …}
length: 1
__proto__: Array(0)
__proto__: Object

And:

return query.get().then(querySnapshot => {
  if (querySnapshot.empty) {
    return { exists: false }
  } else {
    return { exists: true }
  }
})

The console.log:

{data: {…}}
data:
  exists: true
  __proto__: Object
  __proto__: Object

Mabye good to add that I created an (working) index for the query.

Upvotes: 4

Views: 4959

Answers (2)

marcus.salinas
marcus.salinas

Reputation: 993

So to give a clear example of using the .where in the Firebase Functions library for Firebase Cloud Functions

admin.firestore().collection("fruit")
        .where("color", "==", "purple")

With ordering

admin.firestore().collection("fruit").orderBy("size")
            .where("color", "==", "purple")

See demo doc if you want more details about how admin functions

Furthermore, the list of all query functions are found in the Query class can be used from the Firestore Functions library by using method chaining like my two examples in case you'd like things like "limit", "offset", etc.

Upvotes: 0

Doug Stevenson
Doug Stevenson

Reputation: 317352

In both cases, you're returning a promise for an object that isn't what you really want to send to the client. When you write a callable, you need to return a promise that resolves to the exact JavaScript object that you want to send. You can't just return anything. What you'll have to do is convert that querySnapshot into plain old JavaScript objects that describe what you want the client to know. A querySnapshot object itself is not serializable - it is a complex object that describes many things about the query results.

First define this: What exactly do you want the client to receive? Define what the actual JavaScript object should look like. Now, convert the query results to look like that. At a minimum, you can send the entire set of documents as plain JS objects like this:

return query.get().then(querySnapshot => {
    return querySnapshot.docs.map(doc => doc.data());
})

This will return an array to the client with raw document objects. But it's not clear to me that's what you want to send (since you didn't define your expectations). But it's a start.

Upvotes: 7

Related Questions