首页 > 解决方案 > Firestore,安全规则,如何限制地图字段内容数组的大小

问题描述

我在 Firestore 中有这个结构

{
  "fields": ...
  "fields": ...
  "arrayFields":[
     <index 0>
     "field A": ...   
     "field B": ...
     "field C": ...   
     
     <index 1>
     "field A": ...   
     "field B": ...
     "field C": ...

     <index 2>
     "field A": ...   
     "field B": ...
     "field C": ...       
 
  ]
}

它似乎在下面不起作用

if request.resource.data.arrayFields['field A'].size() < 12;

我想限制地图字段数组的大小

标签: firebasegoogle-cloud-firestorefirebase-security

解决方案


Cloud Firestore 安全规则将数组称为List,因此我将在此处使用该术语。

以下规则使用自定义函数来描述我们正在执行的检查:

function doesFieldOfIndexInListHaveSizeLessThan(field, index, list, size) {
  return index + 1 <= list.size()        // is index in list's bounds
    && field in list[index]              // does the target element have the named field
    && list[index][field].size() < size; // does the value of the element's field
                                         // have a size less than the given value
}

doesFieldOfIndexInListHaveSizeLessThan('field A', 0, request.resource.data.arrayFields, 10);

要对多个索引执行此检查,您必须单独编码每个索引,因为安全规则无法迭代。

doesFieldOfIndexInListHaveSizeLessThan('field A', 0, request.resource.data.arrayFields, 10)
  && doesFieldOfIndexInListHaveSizeLessThan('field A', 1, request.resource.data.arrayFields, 10)
  && doesFieldOfIndexInListHaveSizeLessThan('field A', 2, request.resource.data.arrayFields, 10)
  && // and so on...

您可以将它放在另一个函数中,以使条件(而不是实现)更具可读性。在开发自定义函数时,您需要记住它们可以调用其他函数但不能递归,并且它们的总调用堆栈深度限制为 10。将上述规则重写为函数将给出:

function doesFieldInListElementsHaveSizeLessThan(field, list, size, startingOffset, elementsToCheck) {
  return (elementsToCheck > 0 && elementsToCheck <= 10) // elementsToCheck must be between 0 & 10, otherwise fail early
    && startingOffset >= 0 // if starting index is negative, fail early
    && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset, list, size)
    && (elementsToCheck > 1 && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset + 1, list, size)
    && (elementsToCheck > 2 && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset + 2, list, size)
    && (elementsToCheck > 3 && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset + 3, list, size)
    && (elementsToCheck > 4 && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset + 4, list, size)
    && (elementsToCheck > 5 && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset + 5, list, size)
    && (elementsToCheck > 6 && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset + 6, list, size)
    && (elementsToCheck > 7 && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset + 7, list, size)
    && (elementsToCheck > 8 && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset + 8, list, size)
    && (elementsToCheck > 9 && doesFieldOfIndexInListHaveSizeLessThan(field, startingOffset + 9, list, size)
}

// checks first 10 elements to see if their 'field A' is less than 10 characters long
doesFieldInListElementsHaveSizeLessThan('field A', request.resource.data.arrayFields, 10, 0, 10) 
  // checks next 5 elements to see if their 'field A' is less than 10 characters long
  && doesFieldInListElementsHaveSizeLessThan('field A', request.resource.data.arrayFields, 10, 10, 5);

注意:如果您希望您的数组非常大,请使用 Firestore 集合而不是文档中的数组。这将大大简化您的安全规则。


推荐阅读