首页 > 解决方案 > 结构化 Firestore Android 以获取多个 where 检查

问题描述

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

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

我需要阅读所有属于everyDaySciencegeneralKnowledge/或多个标签的问题,如物理、化学等。

我的应用架构如下所示。我如何构建我的数据库以读取多个标签上的集合?

在此处输入图像描述

编辑 我需要有问题的分页,比如,最喜欢的和评论问题。你给我推荐了这个结构

在 MongoDb 中是这样实现的

标签: javaandroidfirebasegoogle-cloud-firestore

解决方案


如果您尝试链接多个whereArrayContains()方法,您很可能会收到以下错误:

原因:java.lang.IllegalArgumentException:无效查询。查询仅支持具有单个数组包含过滤器。

所以不幸的是,Firestore 只能允许一次调用whereArrayContains()方法。在这种情况下,您应该考虑扩充您的数据库结构以允许反向查找,方法是在您的每个标签对象(文档)下添加tagCollection一个名为的新集合tagQuestion,您应该在其中添加所有标有特定标签的问题。您的数据库结构应如下所示:

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

但你会想,为什么要这样做?为什么要复制数据?好吧,就 Firebase 而言,复制数据没有问题。这是一种非常常见的做法,denormalization为此,我建议您观看此视频,Firebase 数据库的非规范化是正常的。这适用于实时数据库,但同样的原则适用于 Cloud Firestore。

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


推荐阅读