Andrey Orlov
Andrey Orlov

Reputation: 39

Firestore query not working

Firestore

Shown above is my firestore collection.

I am attempting to get data from this collection using a Google Cloud Function that I have deployed:

const admin = require('firebase-admin')
const functions = require('firebase-functions')

module.exports=  function(request, response){ 
     let results = []   
     admin.firestore().collection('news_stories')
     .get()
     .then(docs => docs.map(doc => results.push(doc.data())))
     .catch(e => resoponse.status(400).send(e))

      response.status(200).send(results)
}

When I run the above function I get an:

Error: could not handle the request

I also tried running the function this way to see if it would work.

  module.exports=  function(request, response){ 
     let ref = admin.firestore().collection('news_stories')
     .get()
     .then(docs =>   response.status(200).send(docs))
     .catch(e => resoponse.status(400).send(e))
}

This function returned a this JSON object:

return object

There is no information regarding data or any of the docs.

I uploaded the collection to the firestore DB using this function:

const functions = require('firebase-functions')
const admin = require('firebase-admin')

module.exports = function(request,response){
   if(!request.body.data){
      response.status(422).send({error: 'missing data'})
   }
   let data = request.body.data
   data.map(item => { 
      admin.firestore().collection('news_stories').add({item})
      })
     response.status(200).send('success!')
}

Not sure what I am doing wrong. Why is the function not returning any of the documents?

Upvotes: 0

Views: 3487

Answers (2)

Andrey Orlov
Andrey Orlov

Reputation: 39

So after some trouble shooting I found the source of the problem . For some reason if you use .map on the return object the server will respond with a 500 status... change the .map to forEach and the function works

this will work ...

  admin.firestore().collection('news_stories')
    .get()
    .then(docs => {
        let data = []
        docs.forEach(doc => data.push(doc.data()))
       response.status(200).send(data)
  })

yet this wont ...

    admin.firestore().collection('news_stories')
      .get()
       .then(docs => {
         let data = []
         docs.map(doc => data.push(doc.data()))
         response.status(200).send(data)
     })

Upvotes: 1

Frank van Puffelen
Frank van Puffelen

Reputation: 598708

Data is retrieved from Firestore asynchronously. By the time your send you response back to the caller, the results haven't been retrieved from Firestore yet.

It's easiest to see this by replacing the bulk of the code with three log statements:

console.log("Before starting get");
admin.firestore().collection('news_stories')
  .get()
  .then(() => {
    console.log("In then()");
  });
console.log("After starting get");

It's best if you run the above in a regular node.js command, instead of in the Cloud Functions environment, since the latter may actually kill the command before the data is loaded.

The output of the above is:

Before starting get

After starting get

In then()

That is probably not the order that you expected. But because the data is loaded from Firestore asynchronously, the code after the callback function is allowed to continue straight away. Then when the data comes back from Firestore, your callback is invoked and can use the data as it needs to.

The solution is to move all the code that requires the data into the then() handler:

const admin = require('firebase-admin')
const functions = require('firebase-functions')

module.exports=  function(request, response){ 
     admin.firestore().collection('news_stories')
     .get()
     .then(docs => {
       let results = []   
       docs.map(doc => results.push(doc.data()))
       response.status(200).send(results)
     })
     .catch(e => resoponse.status(400).send(e))
}

Upvotes: 2

Related Questions