Firestore - объединение двух запросов локально

Поскольку в Firestore нет логического оператора OR, я пытаюсь объединить 2 отдельных запроса локально.

Теперь мне интересно, как я могу поддерживать правильный порядок результатов. Когда я выполняю 2 запроса независимо, я не могу указать результаты конкретно (по крайней мере, не в том порядке, в котором я получаю результаты из Firestore с помощью метода orderBy).

Моя идея заключалась в том, чтобы поместить второй запрос в onSuccessListener первого запроса. Это плохая идея с точки зрения производительности?

public void loadNotes(View v) {
    collectionRef.whereLessThan("priority", 2)
            .orderBy("priority")
            .get()
            .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                @Override
                public void onSuccess(QuerySnapshot queryDocumentSnapshots) {

                    for (QueryDocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
                        Note note = documentSnapshot.toObject(Note.class);
                        //adding the results to a List
                    }

                    collectionRef.whereGreaterThan("priority", 2)
                            .orderBy("priority")
                            .get()
                            .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                                @Override
                                public void onSuccess(QuerySnapshot queryDocumentSnapshots) {

                                    for (QueryDocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
                                        Note note = documentSnapshot.toObject(Note.class);
                                        //adding the results to a List
                                    }
                                }
                            });
                }
            });
}
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
13
0
5 855
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы объединить 2 отдельных запроса локально, я рекомендую вам использовать метод Tasks.whenAllSuccess(). Вы можете добиться этого, используя следующие строки кода:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query firstQuery = rootRef...
Query secondQuery = rootRef...

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

Как видите, при переопределении метода onSuccess() результатом является list объектов, которые имеют точный порядок задач, которые были переданы в качестве аргументов методу whenAllSuccess().

Есть и другой подход - использовать метод Tasks.continueWith(). Но в зависимости от варианта использования вашего приложения вы можете использовать метод eiter whenAllSuccess() или метод continueWith(). Пожалуйста, посмотрите здесь официальная документация.

Большое спасибо! На самом деле я нашел те же решения в Интернете, но я был очень не уверен, верны ли они, потому что нашел так мало примеров. Теперь, когда вы называете те же самые методы, у меня есть страховка. Одно: я новичок, поэтому у меня проблемы с дженериками, но я заметил, что, когда я пишу Task<List<QuerySnapshot>> combinedTask вместо объявления типа как Task, я получаю List<QuerySnapshot> в OnSucess вместо List<Object, что делает его более удобным. Это правильный способ объявления типа?

Florian Walther 02.05.2018 12:27

Класс QuerySnapshot, как и любой другой класс в Java, расширяет класс Object. Объект класса - это корень иерархии классов. Каждый класс имеет объект в качестве суперкласса. Итак, QuerySnapshot - это объект. В этом случае QuerySnapshot является родственным типом, поэтому не стесняйтесь использовать List<QuerySnapshot>.

Alex Mamo 02.05.2018 13:26

Хорошо, но это лучше, чем заливка objects в onSuccess, или это не имеет значения?

Florian Walther 02.05.2018 13:29

Нет никакой разницы. Пожалуйста, посмотрите это Почта.

Alex Mamo 02.05.2018 13:50

Я просто пытаюсь понять, почему он вообще возвращает это как список объектов. Это потому, что я могу передавать различные задачи в whenAllSuccess?

Florian Walther 02.05.2018 16:55

Он возвращает список объектов, потому что вы вообще не указываете правильный класс. Таким образом, общий класс для списка установлен как корневой класс всех объектов. Каждый класс в Java "является" объектом. Когда вы используете универсальные шаблоны, вы указываете точный тип содержащихся объектов, поэтому список будет содержать объекты типа QuerySnapshot, а не Object. Верно?

Alex Mamo 02.05.2018 17:44

Верно, но метод get на CollectionReference возвращает Task<QuerySnapshot, и я ничего не определяю. Вот почему мне интересно, почему в методе whenAllSucess больше свободы. Как новичок, я просто задаюсь вопросом, разумна ли причина «Я не хочу приводить объекты» для сохранения ее в переменной с универсальным типом.

Florian Walther 02.05.2018 17:45

Да, ты прав. Это происходит потому, что onComplete () определен как onComplete(Task<T> task), и когда вызывается на CollectionReference, он возвращает только Task<QuerySnapshot>, но при вызове на Tasks.whenAllSuccess(firstTask, secondTask) может возвращать список различных типов объектов. Android Studio не знает, что это за объекты, и поэтому возвращает общий список объектов, верно?

Alex Mamo 02.05.2018 18:32

Хорошо, я понимаю, почему Android Studio устанавливает такой тип. Новичку иногда просто сложно понять лучшие практики, и мне интересно, разумно ли определение универсального типа только ради читабельности кода (как я делаю в своем подходе). Но из того, что я читал об общих типах, можно сказать, что одним из преимуществ является отказ от приведения типов, поэтому это кажется разумным.

Florian Walther 02.05.2018 18:38

Да, это. Вы можете пойти по этому пути. Как вы думаете, мой ответ вам помог?

Alex Mamo 02.05.2018 18:39

Да, это решило вопрос и было очень полезно! Спасибо!

Florian Walther 02.05.2018 18:42

@AlexMamo Привет, я могу сделать нумерацию страниц здесь? ограничение 10 на оба запроса? и получить 20 результатов в комбинированном задании?

Surabhi Choudhary 16.02.2020 11:32

@SurabhiChoudhary Вы можете проверить это и это.

Alex Mamo 17.02.2020 09:33

Как в таких случаях рассчитывается плата за чтение? Это для обоих результатов или для комбинированного? Как и в первом фильтре, мы получаем 20 результатов, а во втором, после дополнительной фильтрации, мы получаем 10, поэтому с нас будет взиматься плата за 10, 20 или 30?

Surabhi Choudhary 27.02.2020 15:17

@SurabhiChoudhary Вы будете платить за общее количество элементов, возвращаемых запросами.

Alex Mamo 27.02.2020 15:20

Спасибо @AlexMamo за такой быстрый ответ. Действительно обязан. Последний вопрос, можно ли это использовать со слушателями моментальных снимков?

Surabhi Choudhary 27.02.2020 15:45

@SurabhiChoudhary Нет, только когда вы используете вызов get(), поскольку get() возвращает объект Task.

Alex Mamo 27.02.2020 15:48

@SurabhiChoudhary, как вы передали его в QuerySnapshot, не могли бы вы опубликовать пример, пожалуйста.

Sabeeh Ul Haq 28.03.2020 19:50

@SabeehUlHaq Я не уверен, что понимаю вопрос. Если вам сложно это реализовать, задайте новый вопрос и покажите нам, что вы пробовали. В этом вам помогут я или другие разработчики.

Alex Mamo 29.03.2020 15:30

@AlexMamo, значит, 27 февраля 2020 года ответ будет 10 или 30?

fkvestak 30.03.2021 14:35

@fkvestak 10 или 30 что?

Alex Mamo 30.03.2021 14:41

@AlexMamo кто-то спросил, будем ли мы платить за 10, 20 или 30 результатов в его примере? Скажем, мой первый запрос возвращает 200 результатов, второй - 50, третий - 10. Я визуализирую эти 10 элементов, потому что они удовлетворяют всем 3 запросам. Но сколько я буду платить? 10 прочитанных документов или 260?

fkvestak 30.03.2021 15:00

@fkvestak Вам всегда будет поручено количество операций чтения, равное количеству возвращаемых элементов. Если у вас, например, три запроса, и каждый из них возвращает три документа, вам будет начислено 9 чтений документов.

Alex Mamo 30.03.2021 15:04

@AlexMamo, вот чего я боялся. Это действительно плохо, что делает Firestore практически бесполезным даже для базового приложения TODO.

fkvestak 30.03.2021 15:14

@fkvestak Я думаю, что этот статья предоставит еще больше информации. На самом деле это не то, что вы говорите.

Alex Mamo 30.03.2021 15:18

@AlexMamo, ваша статья выглядит очень красиво, я займусь этим сегодня вечером;)

fkvestak 30.03.2021 15:36

@fkvestak Приятно это слышать;)

Alex Mamo 30.03.2021 16:05

@AlexMamo У вас есть информация / опыт выполнения 2 запросов? Все всегда говорят, что лучше всего запускать 1 запрос и дублировать данные. Я, например, создаю приложение для знакомств и хочу показывать рекомендации профиля клиентам. Мне нужно убедиться, что они еще не видели профиль или он им понравился. Я сохраняю лайки пользователя в собственной коллекции. Поэтому я бы получил 5 профилей, взял идентификаторы и проверил, есть ли они в коллекции пользователей (10 считываний). Для меня это имеет больше смысла, чем повторное сохранение всех данных где-то еще на пользователе, я все равно не смогу получить свои результаты. что ты думаешь

Marcel Dz 31.03.2021 09:16

@MarcelDz Может сработать в вашем сценарии, но если у вас есть что-то особенное, кроме выполнения нескольких запросов (что вполне нормально), разместите новый вопрос здесь, в Stackoverflow, используя его собственный MCVE, чтобы я и другие разработчики Firebase могли вам помочь.

Alex Mamo 31.03.2021 09:22

@AlexMamo, хорошо, я так и сделал, stackoverflow.com/questions/66884058/… с нетерпением ждет вашего вклада. Привет Марсель

Marcel Dz 31.03.2021 10:19

Другие вопросы по теме