Charitha De Silva
Charitha De Silva

Reputation: 23

Retrieving Complex Object from Cloud Firestore Android

I am trying to retrieve a set of complex objects from a Cloud Firestore database. Here is my class:

public class Book {
    private String id;
    private String name;
    private String original;
    private ArrayList<Author> authors;
    private ArrayList<Translator> translators;
    private Series series;
    private Float no;
    private String seriesNo;
    private Integer published;
    private Borrower borrower;
    private Boolean isCollection;
    private Status status;
}

What is the best way to save this Book object to the database? I am currently using the following method.

public void createBook(String userId) {
    FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
    DocumentReference documentReference = firebaseFirestore.collection("books").document();
    Map<String, Object> newBook = new HashMap<>();

    newBook.put("owner", userId);
    newBook.put("id", documentReference.getId());
    newBook.put("name", getName());
    newBook.put("original", getOriginal());
    if (getSeries() != null) {
        Map<String, Object> series = new HashMap<>();
        series.put("id", getSeries().getId());
        series.put("name", getSeries().getName());
        newBook.put("series", series);
    }
    newBook.put("no", getNo());
    newBook.put("seriesNo", getSeriesNo());
    newBook.put("published", getPublished());
    if (getBorrower() != null) {
        Map<String, Object> borrower = new HashMap<>();
        borrower.put("id", getBorrower().getId());
        borrower.put("nameInEnglish", getBorrower().getNameInEnglish());
        borrower.put("nameInSinhalese", getBorrower().getNameInSinhalese());
        borrower.put("mobile", getBorrower().getMobile());
        newBook.put("borrower", borrower);
    }
    newBook.put("isCollection", getIsCollection());
    newBook.put("status", getStatus().toString());

    documentReference
            .set(newBook)
            .addOnSuccessListener(new OnSuccessListener<Void>() {
                @Override
                public void onSuccess(Void aVoid) {
                    for (int i = 0; i < getAuthors().size(); i++) {
                        documentReference.collection("authors").document("author" + i)
                                .set(getAuthors()
                                        .get(i));
                    }

                    for (int i = 0; i < getTranslators().size(); i++) {
                        documentReference.collection("translators").document("translator" + i)
                                .set(getTranslators()
                                        .get(i));
                    }
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                }
            });
}

What is the best way to retrieve the saved values from the database? It's hard to find a good way to access all the values at once. I currently use the following method to retrieve the values excepts for Authors and Translators (which are ArrayLists).

public void getBooks(final BookRetrievable bookRetrievable, String userId) {
    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.setOriginal(documentSnapshot.getString("original"));
                            Series series = new Series();
                            series.setId(documentSnapshot.getString("series.id"));
                            series.setName(documentSnapshot.getString("series.name"));
                            book.setSeries(series);
                            book.setNo(documentSnapshot.getDouble("no").floatValue());
                            book.setSeriesNo(documentSnapshot.getString("seriesNo"));
                            book.setPublished(documentSnapshot.getLong("published").intValue());
                            Borrower borrower = new Borrower();
                            borrower.setId(documentSnapshot.getString("series.id"));
                            borrower.setNameInEnglish(documentSnapshot.getString("series.nameInEnglish"));
                            borrower.setNameInSinhalese(documentSnapshot.getString("series.nameInSinhalese"));
                            borrower.setFacebook(documentSnapshot.getString("series.facebook"));
                            borrower.setMobile(documentSnapshot.getString("series.mobile"));
                            book.setBorrower(borrower);
                            book.setIsCollection(documentSnapshot.getBoolean("isCollection"));
                            book.setStatus(Status.valueOf(documentSnapshot.getString("status")));

                            books.add(book);
                        }

                        books.sort((Book b1, Book b2) -> b1.getName().compareTo(b2.getName()));
                        bookRetrievable.onCallback(books);
                    } else {
                    }
                }
            });
}

Is there anything that I can do better than this and please let me know what is the best way to retrieve ArrayLists in one go?

For easier understanding, I have added screenshots of an example already saved in the database:

example book saved in database - 1

example book saved in database - 2

Thanks in advance!

Upvotes: 2

Views: 1041

Answers (1)

Alex Mamo
Alex Mamo

Reputation: 138969

What is the best way to save this Book object to the database?

The way in which you are adding the data to the data is not wrong. There is no best way to do it. The best solution, is the solution that fits your needs and makes your job easier. If you feel confortable when using a Map, let the code as it is. If you want another approach, I can provide you another solution, which would be to use a model (POJO) class. This is how you Book class should look like:

public class Book {
    private String id;
    private String name;
    private String original;
    private ArrayList<Author> authors;
    private ArrayList<Translator> translators;
    private Series series;
    private Float no;
    private String seriesNo;
    private Integer published;
    private Borrower borrower;
    private Boolean isCollection;
    private Status status;

    public Book() {}

    public Book(String id, String name, String original, ArrayList<Author> authors, ArrayList<Translator> translators, Series series, Float no, String seriesNo, Integer published, Borrower borrower, Boolean isCollection, Status status) {
        this.id = id;
        this.name = name;
        this.original = original;
        this.authors = authors;
        this.translators = translators;
        this.series = series;
        this.no = no;
        this.seriesNo = seriesNo;
        this.published = published;
        this.borrower = borrower;
        this.isCollection = isCollection;
        this.status = status;
    }

    public String getId() { return id; }
    public String getName() { return name; }
    public String getOriginal() { return original; }
    public ArrayList<Author> getAuthors() { return authors; }
    public ArrayList<Translator> getTranslators() { return translators; }
    public Series getSeries() { return series; }
    public Float getNo() { return no; }
    public String getSeriesNo() { return seriesNo; }
    public Integer getPublished() { return published; }
    public Borrower getBorrower() { return borrower; }
    public Boolean getCollection() { return isCollection; }
    public Status getStatus() { return status; }
}

To add this object to the database, just create a new object of Book class and pass to the constructor all those field values.

Is there anything that I can do better than this and please let me know what is the best way to retrieve ArrayLists in one go?

The way you are getting the data from the database using a callback, is correct. There is also no other best way in this case since you cannot return an ArrayList as a result of a method. Due the asynchronous behavior of the Firebase API, this is quite common practice. See here more details.

Upvotes: 2

Related Questions