firebase查询性能orderByChild + .indexOn VS orderByKey

时间:2017-07-13 09:44:39

标签: java firebase firebase-realtime-database

我在这里面临一个非常奇怪的决定,即在处理Firebase数据库时遇到以下情况的表现,我正在做的是生成随机customerId以供替代使用并存储对于那个内部配置文件(我仍然使用Firebase uid,但它仅用于"友好的数字编号&​​#34;正如客户想要的那样。)

我试图做以下其中一项:

当我收到请求时:

UserVO createdUser = Json.fromJson(getRequestBodyAsJson(), UserVO.class);
CompletableFuture<String> checkCustomerIdCompletableFuture = firebaseDatabaseService.buildUniqueCustomerId();
return checkCustomerIdCompletableFuture.thenApply(customerId -> {
    createdUser.setCustomerId(customerId);
    return firebaseDatabaseService.addToUserProfile(createdUser.getId(), getObjectAsMapOfObjects(createdUser));
}).thenCompose(completableFuture -> CompletableFuture.completedFuture(ok(Json.toJson(createdUser))));

customerId始终在配置文件中编入索引:

"profiles":{
   "$uid":{
      ".read":"$uid === auth.uid",
      ".write":"$uid === auth.uid",
      },
    ".indexOn": ["customerId", "email"]
 }

在这两种情况下,用户的个人资料应该是这样的:

"profiles" : {
  "jiac4QpEfggRTuKuTfVOisRGFJn1" : {
    "contactPhone" : "",
    "createdAt" : 1499606268255,
    "customerId" : 4998721187, // OR "A-4998721187" as string
    "email" : "almothafar@example.com",
    "firstName" : "Al-Mothafar",
    "fullName" : "Al-Mothafar Al-Hasan",
    "id" : "jiac4QpEfggRTuKuTfVOisRGFJn1",
    "lastName" : "Al-Hasan2",
    "updatedAt" : 1499857345960,
    "verified" : false
  }
}

buildUniqueCustomerId()我有2个选项:

第一个是直接查询profilescustomerId,并使用queryByChild返回唯一ID,customerId已编入索引:

    public CompletableFuture<String> buildUniqueCustomerId() {
    String customerId = String.valueOf(System.currentTimeMillis()).substring(1, 9).concat(RandomStringUtils.randomNumeric(2));

    CompletableFuture<String> dataSnapshotCompletableFuture = new CompletableFuture<>();
    firebaseDatabaseProvider.getUserDataReference().child("/profiles").orderByChild("customerId").equalTo(customerId).limitToFirst(1)
            .addChildEventListener(new ChildEventListener() {
                @Override
                public void onChildAdded(DataSnapshot snapshot, String previousChildName) {
                    if (snapshot.exists()) {
                        buildUniqueCustomerId();
                    } else {
                        dataSnapshotCompletableFuture.complete(customerId);
                    }
                }

                @Override
                public void onChildChanged(DataSnapshot snapshot, String previousChildName) {
                    if (snapshot.exists()) {
                        buildUniqueCustomerId();
                    } else {
                        dataSnapshotCompletableFuture.complete(customerId);
                    }
                }

                @Override
                public void onChildRemoved(DataSnapshot snapshot) {
                    dataSnapshotCompletableFuture.completeExceptionally(new BusinessException("Child Remove"));
                }

                @Override
                public void onChildMoved(DataSnapshot snapshot, String previousChildName) {
                    dataSnapshotCompletableFuture.completeExceptionally(new BusinessException("Child MOved"));
                }

                @Override
                public void onCancelled(DatabaseError error) {
                    dataSnapshotCompletableFuture.completeExceptionally(new BusinessException(error.getMessage()));
                }
            });
    return dataSnapshotCompletableFuture;
}

另一种方法是,创建像reservedCustomerIds这样的新节点,检查customerId是否已经被保留,并将该id推送到该数组,以防它未被保留并返回ID以供使用,在本例中为{ {1}}是关键:

customerId

第一种方式代码需要一些清理,但它只是快速启动,但你可以看到代码中的第二种方式更短但是存储该ID的又一步,它还有额外的存储空间public CompletableFuture<String> buildUniqueCustomerId() { String customerId = "A-".concat(String.valueOf(System.currentTimeMillis()).substring(1, 9).concat(RandomStringUtils.randomNumeric(2))); String customerRef = String.format("/reservedCustomerIds/%s", customerId); return firebaseDatabaseProvider.fetchObjectAtRef("/usersData".concat(customerRef)) .thenCompose(dataSnapshot -> { if (dataSnapshot.getValue() != null) { return buildUniqueCustomerId(); } else { return CompletableFuture.completedFuture(customerId); } }) .thenCompose((newCustomerId) -> this.updateObjectData(true, customerRef).thenApply(aVoid -> newCustomerId)) .exceptionally(throwable -> { Logger.error(throwable.getMessage()); return null; }); } 仅用于支票ID:

reservedCustomerIds

哪一项性能最佳,更快检查customerId的唯一性?使用customerId作为额外存储的关键,或在"reservedCustomerIds" : { "A-4998721187" : true, "A-4998722342" : true, "A-4998722222" : true, "A-4998724444" : true, "A-4998725555" : true, } 的配置文件中使用customerId本身?

P.S:在评论或完整答案中,如果你能给我一个关于firebase索引或查询的链接,我会非常感激。

1 个答案:

答案 0 :(得分:2)

第二种方法称为fanning out and is covered in the Firebase documentation。它的优点是您可以在不需要查询的情况下读取ID,这意味着其规模没有实际限制。

但是你需要为每个客户做额外的阅读。虽然这些并不像大多数开发人员所期望的那么慢(参见Speed up fetching posts for my social network app by using query instead of observing a single event repeatedly),但总有一个可用性限制。

很难说&#34;这比那更好&#34;。如果有,Firebase实时数据库文档将明确(并且响亮)。但更平坦的结构,散布数据,而不是查询数百万个节点以找到1都有助于拥有一个可以平滑扩展的应用程序。另请参阅Are Firebase queries scalableFirebase Performance: How many children per node?