Android将两个Firestore调用合并到单个回调中

时间:2019-05-16 11:48:15

标签: android google-cloud-firestore rx-java reactive-programming kotlin-coroutines

我目前正在查询Firestore上的某个收藏集,链接此链接

val missionsCollection = FirebaseFirestore.getInstance()
    .collection("/customers").document(user.customerId).collection("missions")
    .orderBy("deadline")
    .whereGreaterThanOrEqualTo("deadline", startDate)
    .whereLessThanOrEqualTo("deadline", endDate)
    .whereArrayContains("staffs", user.id)

为了澄清这些,在我的任务文档中,这些字段分别是:

最后期限:时间戳
员工:带有员工ID的字符串数组

所以我目前要提取的是某个时期(属于某个工作人员)中某个时期(基于截止日期)的所有任务

但是现在,我还必须获取所有员工可见的任务(使用相同的截止日期规则,在此应用程序上,这意味着该数组为空的所有任务

由于我没有称为.whereArrayIsEmpty("staffs")的方法,因此我在文档上创建了一个名为“ visibleToAllStaffs”的字段,它是一个布尔型字段,但是我有一个更深层次的问题。 Firebase不允许使用OR语句。

我知道我可以调用第一个查询,并在它的成功回调中调用第二个查询,但是我想使用比这更好的东西,也许是RxJava或Coroutines,但是我在如何做上陷入了困境这个。

所以,我的问题是:

1)我是否有一种本机方式(仅使用firebase)对两个查询进行分组,这些查询从同一个集合中获取数据,只有一个回调用于错误,一个回调用于成功(在这种情况下,成功将带来两个数据)?

2)如果没有,我可以用RxJava或协程解决吗?怎么样?

编辑

只需给出更多解释,我的第二个电话就是:

val missionsCollection = FirebaseFirestore.getInstance()
    .collection("/customers").document(user.customerId).collection("missions")
    .orderBy("deadline")
    .whereGreaterThanOrEqualTo("deadline", startDate)
    .whereLessThanOrEqualTo("deadline", endDate)
    .whereEqualTo("visibleToAllStaffs", true)

missionsCollection变量是Query类型的对象。在这些对象上,我可以调用get()方法,该方法返回TaskTask<QuerySnapshot>)的QuerySnapshot对象

有了这个Task<QuerySnapshot>对象,我可以添加一些回调(例如成功和错误),如下所示:


missionsCollection.get().addOnSuccessListener { documentSnapshot ->
    val missions = documentSnapshot.map { it.toObject(Mission::class.java) }
    // do something with the list
}.addOnFailureListener {
    // Do something
}

协程的最大问题是尝试合并回调,因为我想我会有这样的东西:

.merge(getMissionsCollection(), getSecondMissionsCollection())
.addOnSuccessListener { documentSnapshot ->
    val missionsFromBothCalls = documentSnapshot.map { it.toObject(Mission::class.java) }
    // do something with the full list
}.addOnFailureListener {
    // Do something
}

但是我找不到像这样的示例(其中的方法返回一个“可观察的”而不是我需要的列表,而我陷入了如何将它们合并在一起的问题。

2 个答案:

答案 0 :(得分:1)

您可以尝试使用协程,如果我没记错的话,我应该看起来更像这样,所以每次暂停都会等到完成为止,然后在启动块中开始下一个。

suspend fun getMissionsCollection() = FirebaseFirestore.getInstance()
     .collection("/customers").document(user.customerId).collection("missions")
     .orderBy("deadline")
     .whereGreaterThanOrEqualTo("deadline", startDate)
     .whereLessThanOrEqualTo("deadline", endDate)
     .whereArrayContains("staffs", user.id)
     .get().await().result

suspend fun getSecondCollection() = FirebaseFirestore.getInstance()
     .
     . 
     .
     .get().await().result

然后使用

launch {
   val missionCollection = getMissionsCollection()
   val secondCollection= getSecondCollection()

   // merge collections or whatever
}

答案 1 :(得分:0)

兄弟你好,你可以看到我的例子。

    private void firebaseTasks() { 

    String audioLink = ""
    String videoLink = ""

    Task taskA = firebase.collection("collectionA").document("docPath")
            .get().addOnSuccessListener(documentSnapshot -> {
                arrayA.addAll((ArrayList<String>) Objects.requireNonNull(documentSnapshot.get("your Field Name")));
                recyclerViewAdapter.notifyDataSetChanged();
            });
    Task taskB = firebase.collection("collectionB").document("docPath1")
            .get().addOnSuccessListener(documentSnapshot -> arrayB.addAll((ArrayList<Boolean>) documentSnapshot.get("your Field Name")));

    Task taskC = firebase.collection("collectionC").document("docPath2")
            .get().addOnSuccessListener(documentSnapshot -> arrayC.addAll((ArrayList<String>) documentSnapshot.get("your Field Name")));

    Task taskD = firebase.collection("collectionD").document("docPath3")
            .get().addOnSuccessListener(documentSnapshot -> arrayD.addAll((ArrayList<String>) documentSnapshot.get("your Field Name")));

    Task taskE = firebase.collection("collectionE").document("docPath4")
            .get().addOnSuccessListener(documentSnapshot -> videoLink = documentSnapshot.getString("your Field Name"));

    Task taskF = firebase.collection("collectionF").document("docPath5")
            .get().addOnSuccessListener(documentSnapshot -> audioLink = documentSnapshot.getString("your Field Name"));

    Tasks.whenAllComplete(taskA, taskB, taskC, taskD, taskE,taskF)
            .addOnCompleteListener(task -> {
                // The task is completed 
            });
}

//如果要循环使用,请尝试以下操作。

    public class FirebaseTaskListExample {

FirebaseFirestore firestore = FirebaseFirestore.getInstance();

    // only these import carefully
    //    import com.google.android.gms.tasks.Task;
    //import com.google.android.gms.tasks.Tasks;

    public void generateTasks(){
    ArrayList<Model> collection = new ArrayList<>();
    List<Task<?>> taskArray = new ArrayList<>();

    collection.add(new Model("aCol","aDoc","aChild"));
    collection.add(new Model("bCol","bDoc","bChild"));

    for(int i = 0; i < collection.size(); i++){
        Task<DocumentSnapshot> task =                 getTask(collection.get(i).collectionName,collection.get(i).docName);
        int finalI = i;
        task.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
            @Override
            public void onSuccess(DocumentSnapshot documentSnapshot) {
                Log.e("Firebase Task 
    Info",documentSnapshot.getString(collection.get(finalI).childDoc));
            }
        });
        taskArray.add(task);
    }

    // after add all tasks set callback

    Tasks.whenAllComplete(taskArray).addOnSuccessListener(new 
     OnSuccessListener<List<Task<?>>>() {
        @Override
        public void onSuccess(List<Task<?>> tasks) {
         // all task is completed
            Log.d("Firebase Task Info","Task Success");
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {

        }
    });

}

    public Task getTask(String col, String doc){
    return firestore.collection(col).document(doc).get();
}

    class Model{
    String collectionName;
    String docName;
    String childDoc;
    Model(String collectionName, String docName,String childDoc){
        this.collectionName = collectionName;
        this.childDoc = childDoc;
        this.docName = docName;
    }
}

}