【问题标题】:how to set validation rules to permit document creation only if documents with the same fields are not present with Cloud Firestore如何设置验证规则以仅在 Cloud Firestore 中不存在具有相同字段的文档时才允许创建文档
【发布时间】:2019-05-25 21:45:58
【问题描述】:

我正在尝试将 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) 会创建一个包含我需要匹配的所有值的复合索引吗?但是我如何编写安全规则,这样我就不必从我的代码中检查或执行获取查询。

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

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

4) 我是否应该在 android 中使用 Device.Id 作为文档 ID 以匹配特定设备,所以如果用户添加了文档,那么他不能添加更多。但这可能会造成文档字段数据的重复。我在问这个关于如何写安全规则,让已经写过文档的人不能再写了。

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

有没有其他更好的方法来解决这个问题...请告诉我。我什至可以使用一些客户端代码来使用 where 子句等,但我想最小化读取配额。如何在使用最小读/写配额的情况下做到这一点。我是 Cloud Firestore 的初学者。

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 所以要明确几个问题:1)为什么我不能创建(字段值的串联)作为具有所有字段值的主集合的文档 ID... 2)如果我创建另一个文档 ID 为(连接的唯一字段值)的集合,那么该集合是否有任何字段或只是一个文档 ID....
    • 3) 我不想对用户进行身份验证,因为我只需要来自用户的某些字段值,但只需要一次且仅当数据不重复时...我也只需要每个设备的数据一次...因此,如果用户删除应用程序、重新安装等,那么我不希望该用户能够在第一次这样做之后添加文档。我还想防止以某种方式将我的代码写入firestore数据库的恶意用户....那么我的android应用程序中firebase的json配置文件会被加密吗?如何让 Firestore 仅检测来自 Play 商店应用的请求?
    • 1) 是可能的。不这样做的主要原因是您更有可能以这种方式达到写入吞吐量限制/延迟。 2)只是文件ID。 3)没有办法限制对“来自您的应用程序”的访问。原因是访问数据库的所有信息都必须在应用程序中,因此恶意用户可以将其复制到他们自己的代码中。如果您希望能够授权特定用户而不是其他用户,则需要进行身份验证。
    猜你喜欢
    • 1970-01-01
    • 2019-03-30
    • 2018-10-01
    • 2018-04-03
    • 2020-12-19
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    • 1970-01-01
    相关资源
    最近更新 更多