14

Is it possible to query firebase for documents in a collection where the number of elements in an array of a particular field is greater than 0

For my example, each document has-a field called 'people', which contains an array of integers (or the array is empty).

My search always return 0 documents, but I have documents that I can see when I search in the firestore database admin panel.

import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
admin.initializeApp();

var db = admin.firestore();
export const helloWorld = functions.https.onRequest(function(req,res)
{
    var all_users = db.collection('users');
    var query = all_users.where("people.length", ">", 0).get().then(snapshot => 
    {
        let docs = snapshot.docs;

        //return 1st document found

        res.send(docs[0].data());
    });

    query.catch(error =>
    {
        res.status(500).send(error);
    });

});
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
aman
  • 499
  • 8
  • 18

3 Answers3

17

This is not possible with Firestore. The only things you can query for array type fields is the exact contents of some element in the array.

Your alternative for filtering on the size of any array is to use an integer field to record the number of elements in the array, and keep it in sync with changes to that array.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Doug Stevenson! thanks for your feedback and a nice proposed solution. Love your videos. – aman Mar 21 '19 at 19:32
  • That is not a valid or correct answer. It is possible to query for not Empty arrays. Although it is not possible to query for empty arrays. Check my answer – Guilherme Ferreira Apr 17 '20 at 06:08
  • @GuilhermeFerreira It is correct. I think you're mistaken about what the query in your answer is actually doing. The length of an array is just not available in Firestore queries. – Doug Stevenson Apr 17 '20 at 06:36
  • The length is indeed not available, but the question is how to "query for documents that contain an array of length > 0". You can do this query without looking at the length property. – Guilherme Ferreira Apr 17 '20 at 06:52
  • You can't do it at all, actually. Your answer is finding map elements by string index, not list elements by numeric index. – Doug Stevenson Apr 17 '20 at 06:54
  • 18
    `.where("myArray", "!=", [])` works for me. Has this capability been added since this answer? – KnewB Nov 16 '20 at 15:44
  • 3
    @KnewB https://stackoverflow.com/questions/47251919/firestore-how-to-perform-a-query-with-inequality-not-equals – Doug Stevenson Nov 16 '20 at 16:08
  • 3
    I'll just add that the Firestore web console only lets me run a != against string, number or boolean, so I thought `"!=", []` wouldn't work but it does : ) – KnewB Nov 16 '20 at 17:10
  • 1
    Hi, I just found this answer and trieed `.where('entries', isNotEqualTo: [])` and that works for me to leave out documents where 'entries' is empty. From your previous answers above I´m not sure if this could have a negative impact? @DougStevenson you link to another thread and I don´t see what you´re pointing at. Thanks – railon Feb 18 '21 at 12:38
5

Indexes are sparse in FS so you can simply do an orderBy and only return documents with populated data on the ordered property:

.collection("users").orderBy("people", "asc")
AndyK
  • 61
  • 1
  • 1
  • Perfect! Thank you! – thecoolwinter Jul 07 '20 at 18:14
  • 1
    This will return all documents without 'people' and then with 'people'. I suggest to use "desc" sort order along with .select('people') and then walk throught the list and save document IDs untill the 'people' is empty. And then get documents with full fields set using IDs. – Viacheslav Dobromyslov Sep 15 '20 at 14:04
0

I was trying to order items in my Firestore Recycler by size of array of people who likes that item. Because there is no such specific query function I created new field "likesNum". To be able to keep it in sync with changes to that array using FieldValue.increment() the field type must be an integer.

But querying a number value field inside .orderBy() was crashing my app. So i tried :

Query query = placesRef.orderBy( String.valueOf("likesNum"), Query.Direction.DESCENDING).limit(5);

And it worked. Although the compiler is saying String.valueOF() is not necessary, my problem is perfectly solved.

Maybe that helps someone with same issue.