6

I'd like to do a collection group query but within a certain path, meaning that I would like to target collections not only with the collectionId but also with where the collection is.

Let's use the example used in the doc to explain it better. We would have landmarks in cities and "general" landmarks in their own collection :

let citiesRef = db.collection('cities');

let landmarks = Promise.all([
  citiesRef.doc('SF').collection('landmarks').doc().set({
    name: 'Golden Gate Bridge',
    type: 'bridge'
  }),
  citiesRef.doc('SF').collection('landmarks').doc().set({
    name: 'Legion of Honor',
    type: 'museum'
  }),
  citiesRef.doc('LA').collection('landmarks').doc().set({
    name: 'Griffith Park',
    type: 'park'
  }),
  citiesRef.doc('LA').collection('landmarks').doc().set({
    name: 'The Getty',
    type: 'museum'
  }),
  citiesRef.doc('DC').collection('landmarks').doc().set({
    name: 'Lincoln Memorial',
    type: 'memorial'
  })
]);

let generalLandmarks = Promise.all([
  db.collection('landmarks').doc().set({
    name: 'National Air and Space Museum',
    type: 'museum'
  }),
  db.collection('landmarks').doc().set({
    name: 'Ueno Park',
    type: 'park'
  }),
  db.collection('landmarks').doc().set({
    name: 'National Museum of Nature and Science',
    type: 'museum'
  }),
  db.collection('landmarks').doc().set({
    name: 'Jingshan Park',
    type: 'park'
  }),
  db.collection('landmarks').doc().set({ 
    name: 'Beijing Ancient Observatory',
    type: 'museum'
  })
]);

Now I would like to query for landmarks that are in a city and not get the general ones. In a simpler way, I would like to do something like this :

let museums = db.collection('cities').collectionGroup('landmarks').where('type', '==', 'museum');

Is it possible ?

Ilan Coulon
  • 1,126
  • 1
  • 7
  • 14
  • 1
    It turns out that searching on a subpath **is** possible after all. Check samthecodingman's answer here: https://stackoverflow.com/a/68049847 – Frank van Puffelen Jun 21 '21 at 16:13

2 Answers2

5

This is currently not possible with Cloud Firestore. When you perform a collection group query, it will use all of the collections and subcollections with the given name. You are not able to narrow to scope of the query to specific collections.

What you can do instead is store a field inside the documents in each subcollection that identify which top-level collection they belong to, then use that field to filter your results.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • 2
    Thank you. Would it be useful to suggest it as a new feature to the Firebase team ? – Ilan Coulon Jul 08 '19 at 13:06
  • 1
    @IlanCoulon It would, please do so... Using a filter like suggested above is a workaround, not a solution. We need a feature where collectionGroups can be restricted to certain paths... otherwise the feature should just be called globalCollection... Silly, ain't it? Feels similar to declaring global variables in Javascript lol. – varun Mar 01 '21 at 14:33
1

Now I would like to query for landmarks that are in a city and not get the general ones.

No, you cannot. Collection group query will return results from all collections or subcollections with the same name, including the general ones. There is no way you can change this.

The solution for that is to change the name of your collections to be different if you want to limit the scope of your collection group query.

If you app is in productuon and you cannot change the name of your collections, simply try to ignore the results that you get client side. How can you achieve this, just take a look a the path of the document and see from which collections belong. In this way you can only use the result from the collection you need.

Another workaround would be to add a new property of type boolean in your collections named isGeneral and set it tu true in the general collection and false in the others. To get only the particular items and not the general once, add to your query a where call:

whereEqualTo("isGeneral", false);
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193