Java 结构化Firestore Android可在多个where检查中获取

Java 结构化Firestore Android可在多个where检查中获取,java,android,firebase,google-cloud-firestore,Java,Android,Firebase,Google Cloud Firestore,我想读取基于多个数组项的集合 db.collection("questionCollection") .orderBy("questionID", Query.Direction.DESCENDING) .whereArrayContains("tags","EveryDayScience") //.whereArrayContains("tags","generalKnowledge")//this

我想读取基于多个数组项的集合

db.collection("questionCollection")
                .orderBy("questionID", Query.Direction.DESCENDING)
                .whereArrayContains("tags","EveryDayScience")
                //.whereArrayContains("tags","generalKnowledge")//this cannot be possible
                .get()
                .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                    @Override
                    public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
                        if (queryDocumentSnapshots.isEmpty()) {
                            Log.d(TAG, "onSuccess: LIST EMPTY");
                            return;
                        } else {
                            // Convert the whole Query Snapshot to a list
                            // of objects directly! No need to fetch each
                            // document.
                            questionList = queryDocumentSnapshots.toObjects(QuestionBO.class);
                        }
                    }
                }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                e.printStackTrace();
                Toast.makeText(mContext,"Failed",Toast.LENGTH_LONG).show();
            }
        });
数据库集合(“问题集合”) .orderBy(“questionID”,Query.Direction.DESCENDING) .WhererrayContains(“标签”、“每日科学”) //.whererrayContains(“标记”、“generalKnowledge”)//这是不可能的 .get() .addOnSuccessListener(新的OnSuccessListener(){ @凌驾 成功时公共无效(QuerySnapshot QueryDocumentSnapshot){ if(queryDocumentSnapshots.isEmpty()){ Log.d(标记“onSuccess:LIST EMPTY”); 返回; }否则{ //将整个查询快照转换为列表 //直接获取对象!无需获取每个对象 //文件。 questionList=queryDocumentSnapshots.ToObject(QuestionBO.class); } } }).addOnFailureListener(新的OnFailureListener(){ @凌驾 public void onFailure(@NonNull异常e){ e、 printStackTrace(); Toast.makeText(mContext,“失败”,Toast.LENGTH_LONG.show(); } }); 我需要阅读所有属于
everyDayScience
generalkknowledge
或物理、化学等多个标签的问题

下面给出了我的应用程序架构。如何构建数据库以读取多个标记上的集合

编辑 我需要有问题的分页,比如,收藏夹和评论问题。 你已经推荐我了


在MongoDb中,如果尝试链接多个
whererrayContains()
方法,很可能会出现以下错误:

原因:java.lang.IllegalArgumentException:查询无效。查询仅支持单个数组包含筛选器

不幸的是,Firestore只能允许对
whererrayContains()
方法进行一次调用。在这种情况下,您应该考虑增加数据库结构,以便在“代码”>标签集合中添加每个标签对象(文档)下的反向查找,这是一个新的集合,名为“代码>标签问题< /代码>,在其中您应该添加用特定标签标记的所有问题。您的数据库结构应如下所示:

Firestore-root
  |
  --- tagCollection (collection)
         |
         --- EveryDayScience (document)
         |    |
         |    --- tagQuestions (collection)
         |          |
         |          --- tagQuestionId
         |                 |
         |                 --- //question details
         |
         --- generalKnowledge (document)
              |
              --- tagQuestions (collection)
                    |
                    --- tagQuestionId
                           |
                           --- //question details
要从两个特定标签获取所有问题,请使用以下代码行:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query firstQuery = rootRef.collection("tagCollection").document("EveryDayScience").collection("tagQuestions");
Query secondQuery = rootRef.collection("tagCollection").document("generalKnowledge").collection("tagQuestions");

Task firstTask = firstQuery.get();
Task secondTask = secondQuery.get();

Task combinedTask = Tasks.whenAllSuccess(firstTask, secondTask).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
    @Override
    public void onSuccess(List<Object> list) {
         //Do what you need to do with the list of questions from within two tags
    }
});
FirebaseFirestore rootRef=FirebaseFirestore.getInstance();
Query firstQuery=rootRef.collection(“tagCollection”).document(“EveryDayScience”).collection(“tagQuestions”);
Query secondQuery=rootRef.collection(“tagCollection”).document(“generalkknowledge”).collection(“tagQuestions”);
Task firstTask=firstQuery.get();
Task secondTask=secondQuery.get();
Task combinedTask=Tasks.whenAllSuccess(第一个任务,第二个任务)。addOnSuccessListener(新OnSuccessListener()){
@凌驾
成功时公开作废(列表){
//在两个标签中对问题列表执行所需操作
}
});
但你会想,为什么要这么做?为什么要复制数据?嗯,当涉及Firebase时,复制数据没有问题。这是一种非常常见的做法,它被命名为
非规范化
,为此,我建议您观看此视频。这适用于实时数据库,但同样的原则也适用于云Firestore


在复制数据时,需要记住一件事。与添加数据的方式相同,您需要对其进行维护。换句话说,如果你想更新/删除一个项目,你需要在它存在的每个地方都这样做。

是的,根据你当时提供给我的详细信息,是的,我给出了我能想到的最佳选择,但现在知道你需要在多个标记后查询数据库,我推荐这种结构。您尝试过使用它吗?用户可能需要筛选两个或更多科目的数据,如数学、物理、化学。第一次,当没有选择主题标签时,我必须显示最像最近的问题。还希望显示用户最喜欢的问题列表。这个结构满足所有要求吗?是的。如果您想筛选两个或多个主题,上述方法将非常有效,但您可以将两个任务传递给
whenAllSuccess()
方法三个任务,甚至一个
列表。如果没有为问题设置标记,那么只需根据日期查询问题节点,并使用10个限制,比如说最后10个问题。如果您想要一个收藏夹列表,那么您应该创建另一个集合,在其中添加所有标记为收藏夹的问题。因此,这个模式确实有助于实现您想要的。我能为您提供其他信息吗?首先,当我将whenAllSuccess()用于everyDayScience和generalKnowledge这两个标记时。它将引出两个问题,都有标签everyDayScience和generalKnowledge。第二,当没有选择标记时,我如何迭代不同标记集合下的问题。如果它将获取问题两次,那么您应该通过检查标记名来删除重复项,如果这是您需要的。如果未选择标记,请创建另一个查询,直接在“问题”集合中搜索问题,对吗?