Я пытаюсь получить набор сложных объектов из Cloud Firestore.
Данные хранятся следующим образом:
У книжного документа есть подколлекции авторов и переводчиков. Чтобы получить полный список книг, необходимо вызвать базу данных следующим образом (я пропустил все другие атрибуты объекта Book и сохранил все, что необходимо для понимания проблемы):
public void getBooks(final BookRetrievable bookRetrievable) {
FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
ArrayList<Book> books = new ArrayList<>();
firebaseFirestore.collection("books")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot documentSnapshot : task.getResult()) {
Book book = new Book();
book.setId(documentSnapshot.getString("id"));
book.setName(documentSnapshot.getString("name"));
book.setStatus(Status.valueOf(documentSnapshot.getString("status")));
documentSnapshot.getReference().collection("authors")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
ArrayList<Author> authors = new ArrayList<>();
for (DocumentSnapshot documentSnapshot : task.getResult()) {
Author author = new Author();
author.setId(documentSnapshot.getString("id"));
author.setNameInEnglish(documentSnapshot.getString("nameInEnglish"));
author.setNameInSinhalese(documentSnapshot.getString("nameInSinhalese"));
author.setWebsite(documentSnapshot.getString("website"));
authors.add(author);
}
book.setAuthors(authors);
documentSnapshot.getReference().collection("translators")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
ArrayList<Translator> translators = new ArrayList<>();
for (DocumentSnapshot documentSnapshot : task.getResult()) {
Translator translator = new Translator();
translator.setId(documentSnapshot.getString("id"));
translator.setNameInEnglish(documentSnapshot.getString("nameInEnglish"));
translator.setNameInSinhalese(documentSnapshot.getString("nameInSinhalese"));
translator.setWebsite(documentSnapshot.getString("website"));
translators.add(translator);
}
book.setTranslators(translators);
books.add(book);
books.sort((Book b1, Book b2) -> b1.getSeriesNo().compareTo(b2.getSeriesNo()));
bookRetrievable.onCallback(books);
} else {
bookRetrievable.onCallback(null);
}
}
});
} else {
bookRetrievable.onCallback(null);
}
}
});
}
} else {
bookRetrievable.onCallback(null);
}
}
});
}
Однако, если я помещаю журналы, кажется, что количество обратных вызовов равно количеству извлеченных книг. Следовательно, есть ли способ оптимизировать этот код таким образом, чтобы был только один обратный вызов для каждой книги и один для каждого документа автора и переводчика?
Заранее спасибо!




Да, есть. Чтобы получить все объекты книги, нет необходимости создавать объект класса Book, вы можете получить его из объекта DocumentSnapshot следующим образом:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference booksRef = rootRef.collection("books");
booksRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
Book book = document.toObject(Book.class);
//Do whay you need to do with your Book object
}
}
}
});
Если вам нужно найти авторов и переводчиков конкретной книги, добавьте в свой класс Book еще два поля: author и translator и соответствующие общедоступные геттеры. Чтобы получить, скажем, переводчик из объекта книги, вы можете использовать следующую строку кода:
Translator translator = book.getTranslator();
Таким же образом можно поступить и с автором.
Author autothor = book.getAuthor();
Рад это слышать. Нет необходимости делать еще один звонок. Вы можете получить их прямо из книжного объекта.
Еще раз спасибо. Теперь в Книжном классе есть: частный автор-автор; частные авторы ArrayList <Author>; частный переводчик-переводчик; частные переводчики ArrayList <Translator>; а также их соответствующие геттеры и сеттеры. Однако я не могу получить из него данные об авторе и переводчике. Например, если вы возьмете вложенную коллекцию «Авторы», в ней есть такие документы, как «author0», «author1» и т. д. Будет ли это гарантировать, что все эти авторы будут извлечены за один раз? Я все еще немного запутался.
Пока объект книги содержит автора и переводчика, вы можете получить его за одну операцию.
да. Я думаю, поскольку у класса книги есть вложенные коллекции, нам нужно выполнить еще один обратный вызов, чтобы собрать всех авторов и переводчиков. Большое спасибо за помощь.
@CharithaDeSilva В итоге с каким решением вы пошли? Я все еще пытаюсь понять это. Большое спасибо!
@AlexMamo Это то, что обнаруживает Firebase? Как это работает?
@Rafael Я выбрал решение, предоставленное Алексом, и оно сработало нормально!
Большое спасибо за ответ. Это уменьшило мой код на 200%. Мой класс книги выглядит следующим образом: общедоступный класс Книга {частный строковый идентификатор; частное строковое имя; частные авторы ArrayList <Author>; частные переводчики ArrayList <Translator>; } Геттеры и сеттеры уже есть. С помощью упомянутого вами метода я смог получить все атрибуты, кроме вложенных коллекций авторов и переводчиков. Мне нужно сделать еще один вызов базы данных, чтобы получить их все?