如何设置验证规则以仅在Cloud Firestore中不存在具有相同字段的文档时才允许创建文档

时间:2019-05-25 21:45:59

标签: android firebase google-cloud-firestore firebase-security-rules

我正在尝试将Cloud Firestore与我的android应用程序一起使用。 所以我要存储3-4个字段。因此,我将以汽车收藏为例。 有一个“汽车”集合。汽车集合的文档包含以下字段: 制造商,型号,最高速度。

我正在使用以下代码通过android添加数据:

dManufacturer = "Hyundai"
dModel = "Kona"
dTopSpeed ="150"
Map<String, Object> car = new HashMap<>();
car.put("manufacturer", dManufacturer);
car.put("model", dModel);
car.put("top_speed",dTopSpeed);


db.collection(cars")
.add(car)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
 @Override
 public void onSuccess(DocumentReference documentReference) {
 Log.d("firebaseab", "DocumentSnapshot added with ID: " + documentReference.getId());
 }
})
.addOnFailureListener(new OnFailureListener() {
 @Override
 public void onFailure(@NonNull Exception e) {
 Log.w("firebaseab", "Error adding document", e);
 }
});

因此,使用我的应用程序的任何用户都只能添加1个汽车文档,并且如果该文档的所有字段值都与集合中的文档相似,则不应添加数据。

我将告诉您我尝试过和正在考虑的选项,但请帮助我告诉您实现此目标的最佳方法是什么,以及如何实现此目标。

因此,我正在考虑通过创建验证安全性规则来实现这一目标,以节省查询配额,以便尽可能地保持在免费计划之内,但我不了解其工作原理,因此我会不断出错或拒绝权限。

我尝试的方式:

1)我尝试编写一个规则,将“!=”与集合中的文档匹配到我从android进行的创建请求中,如上所述,但这给了我错误。我还没有完全了解正在发生的事情。规则就像:

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read;
    }
    // match /{document=**} {
    //   //allow create: if document != request.resource.data;
    //   allow create: if document.manufacturer == "Google";
    // }
    match /cars/{car} {
      allow create : if request.resource.data.manufacturer != resource.data.manufacturer
                    && request.resource.data.model != resource.data.model
                    && request.resource.data.topSpeed != resource.data.topSpeed;

    }
  }
}

但是上面给出了错误,并且无法正常工作。

不知道如何使用!exists在具有相同字段值的文档中进行比较。它们可以具有不同的文档ID,但是如果字段的值相同,那么我不想添加具有相同字段值的另一个文档。

我正在思考但不知道哪种方法正确或如何实施的方法:

1)是否将在其中创建所有需要匹配的值的复合索引?但是我该如何编写安全规则,这样我就不必从代码中检查或执行get查询。

2)我应该将文档ID创建为复合索引吗(但是我应该怎么做以及如何编写安全性验证规则)

3)我是否应该从客户端以“ manufacturer_model_topspeed”格式创建文档ID。所以根据我的例子- “ Hyundai_Kona_150”。这将有助于保持唯一性。如果这样,当输入具有相同文档ID的文档时,该权限将被拒绝。然后我应该如何处理客户。我可以从Cloud Firestore发送描述此特定创建被拒绝事件的特定消息或值吗?

4)我是否应该在android中使用Device.Id作为文档ID来匹配特定设备,所以如果用户添加了文档,则他不能添加更多文档,但这可能会导致文档字段数据重复。有关如何编写安全规则的知识,以便已经写过文档的人不能再次写信。

5)我还想知道是否找到拒绝重复数据的方法,然后如何在android中接收拒绝,让我知道拒绝不是未处理的错误,所以我可以在设备上保存以不与Firestore联系未来。

还有其他更好的方法来解决这个问题吗?请告诉。我什至可以使用一些客户端代码来使用where子句等,但是我想最小化读取配额。如何使用最少的读/写配额执行此操作。我是Cloud Firestore的初学者。

1 个答案:

答案 0 :(得分:0)

安全规则无法查询数据库。因此,无法让您的安全规则在数据库中搜索具有相同字段值的文档。

可以执行的安全规则是检查特定文档的值,或检查特定文档的存在。在这两种情况下,您都必须知道文档的完整路径,包括有关文档的ID。

因此,您可以做的是创建一个附加集合,其中每个文档的键/ ID是要唯一的所有字段值的串联。然后,您的安全规则可以检查此辅助集合中是否已存在文档(通常称为“索引”),如果存在,则禁止写入。

或者,您可以创建执行文档创建的Cloud Function。在您的Cloud Functions代码中,您可以查询数据库,并且仅创建不存在冲突的文档。使用这种方法时,仍然可以让应用直接从数据库中读取并执行更新。