Reputation: 23
I am trying to retrieve a set of complex objects from Cloud Firestore.
The data is stored as follows:
A book document has authors and translators sub-collections. In order to retrieve the complete list of books there is a call to the database as follows (I have omitted all the other attributes of Book object and kept what is necessary to understand the issue):
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);
}
}
});
}
However, if I put Logs it seems like there are callbacks as much as the number of Books that are retrieved. Hence is there a way to optimize this code such that there is only one call back per book and one per every author and translator document?
Thanks in advance!
Upvotes: 3
Views: 157
Reputation: 138969
Yes, there is. In order to get all book objects, there is no need to create an object of Book
class, you can get it from DocumentSnapshot
object like this:
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
}
}
}
});
If you need to get the authors and translators of a specific book, then add in your Book
class two more fileds, author
and translator
and the corresponding public getters. To get, let's say the translator from the book object, you can use the following line of code:
Translator translator = book.getTranslator();
In the same way you can do with the author.
Author autothor = book.getAuthor();
Upvotes: 1