6

I'm building out an app in flutter and I want to run a query to determine if the array in my firestore document is empty. Is there a way to do this?

Here is a picture of my data structured in firestore.

enter image description here

I know there is an arrayContains method but I'm not sure on how to check for an empty array. Here is my current code.

_postsStream = await _firestore
        .collectionGroup('posts')
        .where('timestamp', isGreaterThanOrEqualTo: _start)
        .where('timestamp', isLessThanOrEqualTo: _end)
        .where('problems', arrayContains: )
        .snapshots();

I left the arrayContains: intentionally empty for now. Please advise on how I would go about implementing this feature. Thanks in advance!

eandpi
  • 197
  • 1
  • 9

3 Answers3

15

An empty array defaults to [] So this is possible by doing the following: Do not use ' ' for the square brackets

final _database = Firestore.instance;    

return _database
          .collection('arrays')
          .document(arrId)
          .where('array', isEqualTo: [])
           // .where('array', isNull: true) can be used to check if it's null
          .snapshots()
          .map(_itemListFromSnapshot);
BerlinUkn0w
  • 458
  • 4
  • 8
  • 3
    This is best answer. No need to a new property. I use like this: ref.where('participants', '!=', []) – LacOniC Oct 14 '20 at 21:41
3

You cannot do it in firestore currently. What you can do is.

  • Create a separate property hasProblems which defaults to false.

  • If the user try to register a problem, then check the flag hasProblems.

    • If hasProblems==false, then toggle it to true and add the problem to the list.
    • else no need to toggle, just add the new problem to the list.
    • If problems are to be removed later on, then check for the list to get empty. Once it is empty, then toggle hasProblems back to false.

This way you can achieve what you want-

postsStream = await _firestore
        .collectionGroup('posts')
        .where('timestamp', isGreaterThanOrEqualTo: _start)
        .where('timestamp', isLessThanOrEqualTo: _end)
        .where('hasProblems',isEqualsTo: false)
        .snapshots();

Maybe you can have other better solutions, but this is the one that came in my mind. You can follow the solution @mubin986 has given, but once the list gets bigger and bigger, it impacts performance. Cheers, hope it helps.

Suman Maharjan
  • 1,070
  • 7
  • 14
  • Thank you for the solution! I will definitely implement it in my code and get back to you. As a side question, I realized that even though I delete a user's posts collection entirely and run my code again expecting the user's posts to be gone, I still see them. Why doesn't the stream update with that data removed? – eandpi Mar 21 '20 at 04:55
  • 1
    I am not sure. May be firestore is caching data. – Suman Maharjan Mar 21 '20 at 05:00
  • Perhaps. It's kind of frustrating because I explicitly delete that data, so I expect the data to be gone. Is there any possible way to delete that data from the cache? Do you think waiting a day or so, will fix that? – eandpi Mar 21 '20 at 05:05
  • 1
    https://stackoverflow.com/q/48929728/7532298 Check this may be of help – Suman Maharjan Mar 21 '20 at 05:09
  • Ah ok wonderful. This is perfect. Thanks! Also found this: https://firebase.google.com/docs/firestore/manage-data/enable-offline -- You can set a configuration for offline persistence to false. – eandpi Mar 21 '20 at 05:11
1

There is no way to check with firestore query if an array is empty or not.
But, you can follow these steps:

  • Query the data with range filters:
_postsStream = await _firestore.collectionGroup('posts')
   .where('timestamp', isGreaterThanOrEqualTo: _start)
   .where('timestamp', isLessThanOrEqualTo: _end)
   .snapshots();
  • After fetching the data, iterate over all the DocumentSnapshot and check if problems array is empty or not.
Shariful Islam Mubin
  • 2,146
  • 14
  • 23
  • Can you further explain what you mean by "Query the data with range filters". – eandpi Mar 21 '20 at 04:51
  • 1
    When you use `>, <, >=, <=` these operators in your query, then it's called `range filters`. Here you used `isGreaterThanOrEqualTo: _start` and `isLessThanOrEqualTo: _end`, that's why i mentioned `range filters` – Shariful Islam Mubin Mar 21 '20 at 05:44