Charitha De Silva
Charitha De Silva

Reputation: 23

Retrieving Complex Documents from Cloud Firestore

I am trying to retrieve a set of complex objects from Cloud Firestore.

The data is stored as follows:

database structure

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

Answers (1)

Alex Mamo
Alex Mamo

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

Related Questions