Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select random document from Firestore

I have 1000 documents in a single collection in Cloud Firestore, is it possible to fetch random documents?

Say for example: Students is a collection in Firestore and I have 1000 students in that collection, my requirement is to pick 10 students randomnly on each call.

like image 442
CLIFFORD P Y Avatar asked Jan 22 '18 08:01

CLIFFORD P Y


People also ask

How do I find firestore document ID?

Firebase 9 Firestore Get A Document By ID Using getDoc() Import Firestore Database and de-structure the three methods that we need: getFirestore() → Firestore Database. doc() → It takes references of database, collection name and ID of a document as arguments.

How do I find out how many files are in my firestore collection?

count() allows you to determine the number of documents in a collection or query.

How do I move files from one collection to another in firebase?

Create a copy of the source document in the target collection, i.e. read it from the source collection, get the document fields and create a new document in the target collection with these fields, and then; Delete the document from the source collection.


2 Answers

As per Alex's answer I got hint to get duplicate records from Firebase Firestore Database (Specially for small amount of data)

I got some problems in his question as follow:

  • It gives all the records same as randomNumber is not updated.
  • It may have duplicate records in final list even we update randomNumber everytime.
  • It may have duplicate records which we are already displaying.

I have updated answer as follow:

    FirebaseFirestore database = FirebaseFirestore.getInstance();
    CollectionReference collection = database.collection(VIDEO_PATH);
    collection.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if (task.isSuccessful()) {
                List<VideoModel> videoModelList = new ArrayList<>();
                for (DocumentSnapshot document : Objects.requireNonNull(task.getResult())) {
                    VideoModel student = document.toObject(VideoModel.class);
                    videoModelList.add(student);
                }

                /* Get Size of Total Items */
                int size = videoModelList.size();
                /* Random Array List */
                ArrayList<VideoModel> randomVideoModels = new ArrayList<>();
                /* for-loop: It will loop all the data if you want 
                 * RANDOM + UNIQUE data.
                 * */
                for (int i = 0; i < size; i++) {
                    // Getting random number (inside loop just because every time we'll generate new number)
                    int randomNumber = new Random().nextInt(size);

                    VideoModel model = videoModelList.get(randomNumber);

                    // Check with current items whether its same or not
                    // It will helpful when you want to show related items excepting current item
                    if (!model.getTitle().equals(mTitle)) {
                        // Check whether current list is contains same item.
                        // May random number get similar again then its happens
                        if (!randomVideoModels.contains(model))
                            randomVideoModels.add(model);

                        // How many random items you want 
                        // I want 6 items so It will break loop if size will be 6.
                        if (randomVideoModels.size() == 6) break;
                    }
                }

                // Bind adapter
                if (randomVideoModels.size() > 0) {
                    adapter = new RelatedVideoAdapter(VideoPlayerActivity.this, randomVideoModels, VideoPlayerActivity.this);
                    binding.recyclerView.setAdapter(adapter);
                }
            } else {
                Log.d("TAG", "Error getting documents: ", task.getException());
            }
        }
    });

Hope this logic helps to all who has small amount of data and I don't think It will create any problem for 1000 to 5000 data.

Thank you.

like image 138
Pratik Butani Avatar answered Sep 28 '22 19:09

Pratik Butani


Yes it is and to achieve this, please use the following code:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference studentsCollectionReference = rootRef.collection("students");
studentsCollectionReference.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
    @Override
    public void onComplete(@NonNull Task<QuerySnapshot> task) {
        if (task.isSuccessful()) {
            List<Student> studentList = new ArrayList<>();
            for (DocumentSnapshot document : task.getResult()) {
                Student student = document.toObject(Student.class);
                studentList.add(student);
            }

            int studentListSize = studentList.size();
            List<Students> randomStudentList = new ArrayList<>();
            for(int i = 0; i < studentListSize; i++) {
                Student randomStudent = studentList.get(new Random().nextInt(studentListSize));
                if(!randomStudentList.contains(randomStudent)) {
                    randomStudentList.add(randomStudent);
                    if(randomStudentList.size() == 10) {
                        break;
                    }
                }
            }
        } else {
            Log.d(TAG, "Error getting documents: ", task.getException());
        }
    }
});

This is called the classic solution and you can use it for collections that contain only a few records but if you are afraid of getting huge number of reads then, I'll recommend you this second approach. This also involves a little change in your database by adding a new document that can hold an array with all student ids. So to get those random 10 students, you'll need to make only a get() call, which implies only a single read operation. Once you get that array, you can use the same algorithm and get those 10 random ids. Once you have those random ids, you can get the corresponding documents and add them to a list. In this way you perform only 10 more reads to get the actual random students. In total, there are only 11 document reads.

This practice is called denormalization (duplicating data) and is a common practice when it comes to Firebase. If you're new to NoSQL database, so for a better understanding, I recommend you see this video, Denormalization is normal with the Firebase Database. It's for Firebase realtime database but same principles apply to Cloud Firestore.

But rememebr, in the way you are adding the random products in this new created node, in the same way you need to remove them when there are not needed anymore.

To add a student id to an array simply use:

FieldValue.arrayUnion("yourArrayProperty")

And to remove a student id, please use:

FieldValue.arrayRemove("yourArrayProperty")

To get all 10 random students at once, you can use List<Task<DocumentSnapshot>> and then call Tasks.whenAllSuccess(tasks), as explained in my answer from this post:

  • Android Firestore convert array of document references to List<Pojo>
like image 38
Alex Mamo Avatar answered Sep 28 '22 19:09

Alex Mamo