1

I have a database in Firestore and RecycleView to put the data from it. I send some query to Firestore and it get me the result depending on my request. But what, if I want to take 3 random results from the set issued to me on request. That is I get, for example, 20 results and want to take only 3 result each time when I send a request. And each time, it must be random 3 results from this 20?

I found there only one solution of the same problem:

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<Students> studentList = new ArrayList<>();
            for (DocumentSnapshot document : task.getResult()) {
                Student student = document.toObject(Student.class);
                studentList.add(student);
            }

            int studentCount = studentList.size();
            int randomNumber = new Random().nextInt(studentCount);

            List<Students> randomStudentList = new ArrayList<>();
            for(int i = 1; i < 10; i++) {
                randomStudentList.add(studentList.get(randomNumber));
            }
        } else {
            Log.d(TAG, "Error getting documents: ", task.getException());
        }
    }
});

But this is about how to take some random data from Firestore, not from the sample of data on request. So does it some solution for it?

My RecycleView class:

    public class Myactivity extends AppCompatActivity {

    public RecyclerView mResultList;
    public FirebaseFirestore mFirestore;
    public com.google.firebase.firestore.Query query;
    public FirestoreRecyclerAdapter<Places, PlaceViewHolder> firestoreRecyclerAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycle_activity);
        mResultList = findViewById(R.id.list_result);

        Boolean l_check1 = getIntent().getExtras().getBoolean("1");
        Boolean l_check2 = getIntent().getExtras().getBoolean("2");
        Boolean l_check3 = getIntent().getExtras().getBoolean("3");
        mFirestore = FirebaseFirestore.getInstance();  
        if (l_check1) {
            query = mFirestore.collection("Places").whereEqualTo("colour", "1").limit(20);
            query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                    List<Places> placesList = new ArrayList<>();
                    for (DocumentSnapshot document : task.getResult()) {
                        Places place = document.toObject(Places.class);
                        placesList.add(place);
                    }
                    int placeCount = placesList.size();
                    int randomNumber = new Random().nextInt(placeCount);

                    List<Places> randomPlaceList = new ArrayList<>();
                    for (int i=1; i<=3; i++) {
                        randomPlaceList.add(placesList.get(randomNumber));
                    }
                }
            }
        });
        } else if (l_check2) {
            query = mFirestore.collection("Places").whereEqualTo("colour", "2").limit(3);
        } else if (l_check3) {
            query = mFirestore.collection("Places").whereEqualTo("colour", "3").limit(3);
        }
mResultList.setLayoutManager(new LinearLayoutManager(this));
        FirestoreRecyclerOptions<Places> options = new FirestoreRecyclerOptions.Builder<Places>()
                .setQuery(query, Places.class)
                .build();
        firestoreRecyclerAdapter = new FirestoreRecyclerAdapter<Places, PlaceViewHolder>(options) {
            @Override
            protected void onBindViewHolder(PlaceViewHolder holder, int position, Places model) {

                holder.setDetails(getApplicationContext(), model.getName(), model.getImage());
            }

            @Override
            public PlaceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.list_layout, parent, false);
                return new PlaceViewHolder(view);
            }

        };
        mResultList.setAdapter(firestoreRecyclerAdapter);
    }
    @Override
    protected void onStart() {
        super.onStart();
        firestoreRecyclerAdapter.startListening();
    }
    class PlaceViewHolder extends RecyclerView.ViewHolder {

        View mView;

        public PlaceViewHolder(View itemView) {
            super(itemView);

            mView = itemView;
        }

        public void setDetails(Context context, String placeName, String placeImage) {

            final TextView place_Name = mView.findViewById(R.id.text_image_id);
            ImageView place_Image = mView.findViewById(R.id.image_id);

            place_Name.setText(placeName);
            Glide.with(context).load(placeImage).into(place_Image);

            place_Name.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(getApplicationContext(), Card_activity.class);
                    intent.putExtra("qwerty", place_Name.getText());
                    startActivity(intent);
                }
            });
        }
    }
    @Override
    protected void onStop() {
        super.onStop();
        if (firestoreRecyclerAdapter != null) {
            firestoreRecyclerAdapter.stopListening();
        }
    }
}

There I take some Extra from another activity and based on this result and checking it in if loop, I make a query in Firestore, then from the search sample I take 3 results, grab the "name" and "image" fields and set them in the RecycleView. But if the conditions are the same, then the result is the same, just take the first 3 fields from Firestore in order of their placement there and if they fit the conditions, they are displayed in RecycleView. I need so that each time, it 3 results will be random.

EDITED:My Place_class:

public class Places {
private String image, name;
public Places() { }

public Places(String image, String name) {
    this.image = image;
    this.name = name; 
}
public String getImage() { return image; }
public String getName() { return name; }   
}
Spike Johnson
  • 365
  • 4
  • 12

1 Answers1

2

I see that you have used the exact answer from here, which was actually written by me. That answer can be modified in a very simple way to achieve what you want but you need to use a Query. So please add/modify the following lines of code:

Query query = studentsCollectionReference.orderBy("name").limit(20);
query.get().addOnCompleteListener(/* ... */);

And then change the for loop to return only 3 random records like this:

List<Students> randomStudentList = new ArrayList<>();
for(int i = 1; i <= 3; i++) {
    randomStudentList.add(studentList.get(randomNumber));
}
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Thanks @Alex Mamo, I understand you logic in that, but how to conect this creating of `ArrayList` and put them all 20 records from `Firestore`, to my already used `query`? I need to put in the `ArrayList` exactly sample of my `query` with contidions, like my `whereEqualTo("color", "1")`... – Spike Johnson May 03 '18 at 12:12
  • And I don't clearly understand, your `List`, this `Student` it's my model class with `get`, `set` methods? Can I use my own `class` with this methods?@Alex Mamo – Spike Johnson May 03 '18 at 12:15
  • Did you mean, that after my own `query`, with my condition, i must to add `.addOnComleteListener(`)? But what is about I have thousands queries? I must to add it each time?@ Alex Mamo – Spike Johnson May 03 '18 at 12:22
  • This is only an example. You should use instead of `Students` class, your model class `PlaceList`. Then use the exact query that you want to use, and just add the result to that ArrayList. "But what is about I have thousands queries". When you query, it means that you need to filter the data. If you have too many queries, just pass the variable that is chaning constantly to the desired method (e.g. `.whereEqualTo("colour", numberOfColor)`). – Alex Mamo May 03 '18 at 12:36
  • I Edited my question, all works but nothing changed. All 20 variants dispayed, each time in in the same sequence.@Alex Mamo – Spike Johnson May 03 '18 at 14:33
  • I see now. This is happening because you are using to create the `options` object a query which has no constraints. In order to solve this, you need to use in your adapter, the `randomPlaceList` which contains those 3 random items or to restrict this inside the adapter where you are setting the views. – Alex Mamo May 03 '18 at 14:41
  • It is to broad to explain step by step in a few words. I just gave you an idea on how you can achieve this... – Alex Mamo May 03 '18 at 15:20
  • I'm sorry, just try `RecycleView` first time, it because i didn't understand you. I think, that i must use `randomPlaceList` instead of something. Instead of `Places.class` or what?@Alex Mamo – Spike Johnson May 03 '18 at 15:26
  • Can you tell me please, at least with it I must start? Now my `adapter` is conect to `Place.class` but must be connect to `randomPlaceList`?@Alex Mamo – Spike Johnson May 03 '18 at 19:32
  • Or do I need to create new class `randomPlaceList`, where must put `set`, `get` methods?@Alex Mamo – Spike Johnson May 03 '18 at 19:33
  • Can you give an advice?@Alex Mamo – Spike Johnson May 04 '18 at 10:48
  • As I told you, it is to broad to answer here. It does help you if I provide you code that uses a ListView instead of RecyclerView? It's much easier. – Alex Mamo May 04 '18 at 10:50
  • Oh, Will I be able to edit the `RecycleView` in his sample? I'm will be very grateful ti your, it's my last comlex problem of my project..@Alex Mamo – Spike Johnson May 04 '18 at 10:53
  • Yesterday I began watching your videos about making shoping app, in this lessons, can I find the answer?@Alex Mamo – Spike Johnson May 04 '18 at 10:56
  • I told you about a ListView and not a RecyclerView. That tutorial will help you get better understanding about how you can retrieve data from a Cloud Firestore database and display it in a `RecyclerView` using `FirestoreRecyclerAdapter`. The random problem you can solve using my answer above. – Alex Mamo May 04 '18 at 11:04
  • So can you provide me code about ListVIew?@Alex Mamo I think, that it is not so big problem to integrate your code above, but I was wrong.. Maybe there are some simplier path to slove this problem. For example, to give random ID to all record in Firestore, and ordered it by ascending like in this answer https://stackoverflow.com/questions/46798981/firestore-how-to-get-random-documents-in-a-collection @Alex Mamo – Spike Johnson May 04 '18 at 11:15
  • Please @Alex Mamo, you already once helped me very much, so will do this at least one time again, you are professional, i'm just 3 month in this industry. Give me a reason to believe in humanity)) – Spike Johnson May 04 '18 at 11:19
  • My `randomPlaceList` must becom a Model class, right? And Holder will remain the same. So in my logic, i must create this model class `randomPlaceList`, put there `get`methods, and will do, that Adapter, take take data through this clas..@Alex Mamo – Spike Johnson May 04 '18 at 11:40
  • No, your `randomPlaceList` should containt your model class objects. Try to understand the logic of my code. – Alex Mamo May 04 '18 at 12:21
  • You create an `ArrayList`(placeList), then put there objects of class `Place`(my model class), then you learn the number of elements in this `ArrayLis`t and based on this, you create a variable with a random number. Then create a new `ArrayList` and add there three random elements from the previously created masivve. I understand, but what's wrong with my `options` object? How I can use `randomPlaceList`, if my adapter already use `Place`.class for data and `Holder` for take views? Where do I apply this `randomPlaceList` or instead?@Alex Mamo – Spike Johnson May 04 '18 at 13:49
  • You understood correct! But this is happening inside `onComplete` method and do not affect waht you are passing to the `options` object. that's why you always have 20 elements. Try to log the `randomPlaceList ` and see what contains, only there elements. So you need to use that list to display elements. – Alex Mamo May 04 '18 at 14:25
  • Have you solved the issue? Is there everything alright? – Alex Mamo May 07 '18 at 07:23
  • Hi @Alex Mamo, unfortunately, not yet. I asked other people, but such a feeling that no one has ever encountered with this task... – Spike Johnson May 07 '18 at 07:27
  • @SpikeJohnson Hope this link will be helpful : https://stackoverflow.com/a/58023128/1318946 – Pratik Butani Sep 20 '19 at 06:53