title: Firestore Security Rules for Query with Array Contains
body: <p>I have a Flutter app in which users can make posts and tag the post as belonging to a group. Posts are stored in a global collection and each has a <code>Post.groupId</code> field:</p>
  
  <pre><code>/posts/{postId}
  </code></pre>
  
  <p>Based on my Firestore security rules and queries, users are only allow to read posts if they are in the group for which the post is tagged (i.e the posts's <code>groupId</code> field). Approved group users are stored in:</p>
  
  <pre><code>/groups/{groupId}/users/{userId}
  </code></pre>
  
  <p>I could query the posts from a particular user's group like:</p>
  
  <pre><code>_firestore.collection('posts').where('groupId', isEqualTo: 'groupA')...
  </code></pre>
  
  <p>This above was all working properly.</p>
  
  <p>I am attempting to make an improvement in which a post can be tagged in multiple groups instead of just one, so I am replacing the single <code>Post.groupId</code> field with a <code>Post.groupIds</code> array. A user should be able to read a post if he/she is a member of ANY of the groups from <code>Post.groupIds</code>. I attempt to read all posts tagged with a particular group with the following query from my Flutter app:</p>
  
  <pre><code>_firestore.collection('posts').where('groupIds', arrayContains: 'groupA')...
  </code></pre>
  
  <p>I keep receiving the following exception <code>Missing or insufficient permissions</code> with these security rules:</p>
  
  <pre><code>match /posts/{postId} {
      allow read: if canActiveUserReadAnyGroupId(resource.data.groupIds);
  }
  
  function isSignedIn() {
      return request.auth != null;
  }
  
  function getActiveUserId() {
      return request.auth.uid;
  }
  
  function isActiveUserGroupMember(groupId) {
      return isSignedIn() &amp;&amp;
              exists(/databases/$(database)/documents/groups/$(groupId)/users/$(getActiveUserId()));
  }
  
  function canActiveUserReadAnyGroupId(groupIds) {
      return groupIds != null &amp;&amp; (
              (groupIds.size() &gt;= 1 &amp;&amp; isActiveUserGroupMember(groupIds[0])) ||
              (groupIds.size() &gt;= 2 &amp;&amp; isActiveUserGroupMember(groupIds[1])) ||
              (groupIds.size() &gt;= 3 &amp;&amp; isActiveUserGroupMember(groupIds[2])) ||
              (groupIds.size() &gt;= 4 &amp;&amp; isActiveUserGroupMember(groupIds[3])) ||
              (groupIds.size() &gt;= 5 &amp;&amp; isActiveUserGroupMember(groupIds[4]))
              );
  }
  </code></pre>
  
  <p>With these security rules I can read a single post but I cannot make the above query. Is it possible to have security rules which allow me to make this query?</p>
  
  <p><strong>UPDATE 1</strong></p>
  
  <p>Added <code>isSignedIn()</code> and <code>getActiveUserId()</code> security rules functions for completeness.</p>
  
  <p><strong>UPDATE 2</strong></p>
  
  <p>Here is the error I am receiving when I attempt to execute this query with the Firestore Emulator locally:</p>
  
  <pre><code>     FirebaseError: 
  Function not found error: Name: [size]. for 'list' @ L215
  </code></pre>
  
  <p>Line 215 corresponds to the <code>allow read</code> line within this rule:</p>
  
  <pre><code>match /posts/{postId} {
      allow read: if canActiveUserReadAnyGroupId(resource.data.groupIds);
  }
  </code></pre>