Ali Özen
Ali Özen

Reputation: 83

How to make an ArrayList with two Firestore collection?

I would like to load RecyclerView from my firestone db. My firestore structure is like this:

users(collection) -> user_id(document) -> books(collection)
books(collection) -> book_id(document)

Added: Database structure images
enter image description here
enter image description here
enter image description here

What I want to do is getting the book_ids of current_user into an ArrayList<String> then with this arraylist and for each loop, I want to load books into another ArrayList<Book>. I am getting the “ArrayList book_ids” of the current user. (I want to show the books which were added by current user)
The problem is with this array list I can not manage to get ArrayList<Book>books. I will send this array list to recycler view adapter.

        public void getBookIdsFromDb(){
    final ArrayList<String> myBookIds = new ArrayList<String>();

    CollectionReference bookIdRef = db.collection(getString(R.string.collection_users)).document(userId)
            .collection(getString(R.string.colleciton_books));

    bookIdRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull com.google.android.gms.tasks.Task<QuerySnapshot> task) {
            if (task.isSuccessful()){
                for (DocumentSnapshot ds : task.getResult()){
                    myBookIds.add(ds.getString("book_id"));
                   myBookIds.size());
                }
                Log.d(TAG, "onComplete: myBookIds.size" + myBookIds.size());
                if (myBookIds.size()>0){
                    getMyBooksFromDb(myBookIds);
                    //this works
                }


            }
        }
    });
}
public void getMyBooksFromDb(ArrayList<String> bookIds){
    final ArrayList<String> myBooksIds =bookIds;
    final ArrayList<Book> myBooks = new ArrayList<Book>();

    CollectionReference dbRef = db.collection(getString(R.string.colleciton_books));
    for (int i =0; i<myBooksIds.size();i++){
        Log.d(TAG, "getMyBooksFromDb: myBookIds in for " + myBooksIds.size());

dbRef.document(myBooksIds.get(i)).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
            @Override
            public void onSuccess(DocumentSnapshot documentSnapshot) {
                if (documentSnapshot != null){
                    Book myBook = documentSnapshot.toObject(Book.class);
                    myBooks.add(myBook);
                    //Can not get out of this array from for loop
                }

            }
        });
    }

}


//I tried to make a nested query below but no result :(

  public void getBookListFromDb(){
    final ArrayList<String> myBookIds = new ArrayList<String>();

    CollectionReference bookIdRef = db.collection(getString(R.string.collection_users)).document(userId)
            .collection(getString(R.string.colleciton_books));

    bookIdRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull com.google.android.gms.tasks.Task<QuerySnapshot> task) {
            final ArrayList<Book> myBooks = new ArrayList<Book>();
            if (task.isSuccessful()){
                for (DocumentSnapshot ds : task.getResult()){
                    myBookIds.add(ds.getString("book_id"));
                    myBookIds.size();
                }
                Log.d(TAG, "onComplete: myBookIds.size" + myBookIds.size());
                if (myBookIds.size()>0){
                    CollectionReference colRef = db.collection(getString(R.string.colleciton_books));
                    for (int i=0; i< myBookIds.size(); i++){

                        colRef.document(myBookIds.get(i)).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                            @Override
                            public void onComplete(@NonNull com.google.android.gms.tasks.Task<DocumentSnapshot> task) {
                                if (task.isSuccessful()){
                                    DocumentSnapshot ds = task.getResult();
                                    Book myBook = ds.toObject(Book.class);
                                    myBooks.add(myBook);
                                }

                                Log.d(TAG, "onComplete: myBooks.size(i) "+ myBooks.size());
                            }
                        });
                        Log.d(TAG, "onComplete: myBooks.size() in for "+ myBooks.size());
                    }

                    Log.d(TAG, "onComplete: myBooks.size() "+ myBooks.size());

                }


            }
        }
    });
}'

Upvotes: 1

Views: 2477

Answers (2)

Alex Mamo
Alex Mamo

Reputation: 138824

You cannot achieve what you want in this way because both methods, onComplete() and onSuccess() have an asynchronous behaviour. This means that by the time you are calling getMyBooksFromDb() method, you haven't finished getting the data from the database. So to solve this, you need to move all your logic from your getMyBooksFromDb() method inside onComplete() method. This is the flow:

  • add a complete listener on your bookIdRef
  • get all the book_id you have in your database by iteration using the foor loop
  • inside onComplete() method use the book_id to create your CollectionReference for finding the books.
  • Move the declaration of your ArrayList<Book> inside onSuccess() method.
  • Do what you want to do with your list or with your Book objects.

So the solution is to use nested queries as explained above. So please use the following code:

CollectionReference bookIdRef = db.collection(getString(R.string.collection_users))
    .document(userId)
    .collection(getString(R.string.colleciton_books));

bookIdRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
    @Override
    public void onComplete(@NonNull com.google.android.gms.tasks.Task<QuerySnapshot> task) {
        if (task.isSuccessful()){
            for (DocumentSnapshot ds : task.getResult()) {
                String bookId = myBookIds.add(ds.getString("book_id"));

                dbRef.document(bookId).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
                    @Override
                    public void onSuccess(DocumentSnapshot documentSnapshot) {
                        if (documentSnapshot != null){
                            Book myBook = documentSnapshot.toObject(Book.class);
                            Log.d("TAG", myBoog.getBookName());
                        }
                    }
                });
            }
        }
    }
});

Upvotes: 1

Tapan Kumar Patro
Tapan Kumar Patro

Reputation: 767

Step -1:

Create a Model Class of Userbook.java and Book.java

Userbook.Java

String book_id;
Book book;

//create getter and setter for that.

As per you code set value:

UserBook userbook = new UserBook();

final ArrayList<UserBook> books = new ArrayList<String>();

public void getBookIdsFromDb(){


    CollectionReference bookIdRef = db.collection(getString(R.string.collection_users)).document(userId)
            .collection(getString(R.string.colleciton_books));

    bookIdRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull com.google.android.gms.tasks.Task<QuerySnapshot> task) {
            if (task.isSuccessful()){
                for (DocumentSnapshot ds : task.getResult()){
                   userbook.setBook_id(ds.getString("book_id"));

                }
                Log.d(TAG, "onComplete: myBookIds.size" + myBookIds.size());
                if (myBookIds.size()>0){
                    getMyBooksFromDb(myBookIds);
                    //this works
                }


            }
        }
    });
}
public void getMyBooksFromDb(ArrayList<String> bookIds){

    CollectionReference dbRef = db.collection(getString(R.string.colleciton_books));
    for (int i =0; i<myBooksIds.size();i++){
        Log.d(TAG, "getMyBooksFromDb: myBookIds in for " + myBooksIds.size());
        dbRef.document(myBooksIds.get(i)).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
            @Override
            public void onSuccess(DocumentSnapshot documentSnapshot) {
                if (documentSnapshot != null){
                    Book myBook = documentSnapshot.toObject(Book.class);

                    userbook.setBook_id(myBook);
                    //Can not get out of this array from for loop
                }

            }
        });
    }

}
//after all this add obj to list
books.add(userbook);

I hope you will get the result. or else ping here.

Upvotes: 0

Related Questions