Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Query Collection And Merge Subcollection Data

I'm trying to figure out a way to get a collection of documents along with their subcollection data.

For example, my tree is...

-locations
 -{locationId}
   -historic
     -april
       -airTemp: 12.4
       -displayOrder: 4
     -august
       -airTemp: 14.5
       -displayOrder: 9
     -december
       -airTemp: 13.5
       -displayOrder: 12
     etc..

...where locationId is a document and historic is the subcollection with monthly documents in it.

I know how to get the top level collection items and store it into an array but I want to add their subcollection data (i.e. the jan, feb, etc.) into each document as well.

  var locations = []

  let ref = db.collection('locations')
  db.collection('locations').get()
  .then(snapshot => {
      snapshot.forEach(doc => {
          let location = doc.data()
          location.id = doc.id
          location.name = doc.name

          // get the historic subcollection data here

      })
  })

How can I get the combined data (collection and subcollection) from each object and then push it into an array?

bounty is wrong structure each month should be its own object

like image 720
pjmanning Avatar asked Oct 23 '18 08:10

pjmanning


1 Answers

There is no way, with the mobile/web client libraries, to get, in one query, the data of a Firestore document and the data of its sub-collection(s) documents.

There is even no way to get the list of the sub-collections of a document (with the mobile/web client libraries), see https://firebase.google.com/docs/firestore/query-data/get-data#list_subcollections_of_a_document

So you need to know the name of the sub-collections in order to query them, which is your case (name = 'historic').

You could do as follows. First you get all the parent documents and at the same time you use Promise.all() to query, in parallel, all the 'historic' sub-collections.

    var db = firebase.firestore();

    var promises = []
    db.collection('locations').get()
        .then(snapshot => {
            snapshot.forEach(doc => {
                let location = doc.data()
                location.id = doc.id
                location.name = doc.data().name
                console.log(location);
                promises.push(doc.ref.collection('historic').get());
            })
            return Promise.all(promises);
        })
        .then(results => {
            results.forEach(querySnapshot => {
                querySnapshot.forEach(function (doc) {
                    console.log(doc.id, " => ", doc.data());
                });
            });
        });

Note that the order of the results array is exactly the same than the order of the promises array.

Also note that to get the value of a document item (e.g. name) you need to do doc.data().name and not doc.name.

like image 171
Renaud Tarnec Avatar answered Sep 28 '22 07:09

Renaud Tarnec