【问题标题】:Android merging two Firestore calls into single callbackAndroid将两个Firestore调用合并为单个回调
【发布时间】:2019-05-16 11:48:14
【问题描述】:

我目前正在 Firestore 上查询一个集合链接这个:

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

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

截止日期:时间戳
staffs:一个带有staff id的字符串数组

所以我目前正在获取的是属于某个员工的某个时间段(基于截止日期)的所有任务

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

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

我知道我可以调用第一个查询,并在它的成功回调上调用第二个查询,但我想使用比这更好的东西,也许是 RxJava 或 Coroutines,但我不知道该怎么做这个。

所以,我的问题是:

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

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

编辑

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

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() 方法,该方法返回QuerySnapshotTask 对象(Task<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
}

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

【问题讨论】:

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


    【解决方案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
    }
    

    【讨论】:

    • 非常感谢,但我对协程最大的问题是尝试合并两个回调,因为get() 方法给了我一个Task,而不是一个List。如果我编辑我的问题,解释我的第二个查询应该如何,并详细说明 get 方法的返回,你能帮我解决这个问题吗?
    • 不能保证,让我们试试吧:D
    • 我尽可能多地编辑了这个问题。我真的很喜欢你已经回答的问题,但是对协程的新鲜感会让一些概念变得难以理解,比如合并两个返回“可观察”的挂起函数
    • 可观察是什么意思?你想看看数据库中的数据是否发生了变化吗?您是否在 Firestore 中看到实时更新 -> firebase.google.com/docs/firestore/query-data/listen
    • 我实际上是在使用这个实现:firebase.google.com/docs/firestore/query-data/get-data
    【解决方案2】:

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

        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;
        }
    }
    

    }

    【讨论】:

    • 请阅读this
    • 我可以把这段代码放在for循环中吗?为了以编程方式生成任务数量。
    • 是的,您可以以编程方式生成任务数量。我也更新了代码,你可以看看例子。你
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多