0

I'm trying to return random element in Spring using Query.

I have this:

@Override
public List<AdventureHolidays> findRandomTrekking() {
    Query query = new Query();
    query.addCriteria(Criteria.where("typeOfAdventureHolidays").is("trekking"));
    return mongoTemplate.find(query, AdventureHolidays.class);
}

But this return me all elements that match my criteria,

I tried with:

return mongoTemplate.findOne(query, AdventureHolidays.class); but then I have required type List provided AdventureHoliday

Also I was using and tried with this, but on this way elements appear twice sometimes:

@Aggregation(pipeline = {"{'$match':{'typeOfAdventureHolidays':'trekking'}}", "{$sample: 
{size:1}}"})

So I find a way with this Query, but its listing me all documents while I want just one random from collection

gawi
  • 2,843
  • 4
  • 29
  • 44

1 Answers1

0

After some discussion this is what OP asked for:

private static Queue<AdventureHolidays> elementsToReturn = new LinkedList<>();

public AdventureHolidays findRandomTrekking() {
  if (elementsToReturn.size() == 0) { //fetch data from db
    Query query = new Query(); 
    query.addCriteria(Criteria.where("typeOfAdventureHolidays")
         .is("trekking"));
    List<AdventureHolidays> newData = mongoTemplate.find(query, AdventureHolidays.class)
    Collections.shuffle(newData);
    elementsToReturn.addAll(newData);
  }
  return elementsToReturn.poll(); //this will crash if database is empty
}

Original answer.

You need to change return type of a method:

public AdventureHolidays findRandomTrekking() {
  Query query = new Query();
  query.addCriteria(Criteria.where("typeOfAdventureHolidays").is("trekking"));
  return mongoTemplate.findOne(query, AdventureHolidays.class);
}
gawi
  • 2,843
  • 4
  • 29
  • 44
  • Hi, thanks for help. I also created like that, but problem is I always get same document from collection even I have more then one, and also, when I call API again document is not changed. What I mean is: I have for example A, B, C. When I start app its always A first and on every API call its always A. It should be random on first app start and on every API call new random document – Stefan Jankovic Aug 12 '22 at 18:16
  • If randomness is an issue then maybe this can help you: https://stackoverflow.com/questions/35976725/random-documents-from-mongodb-using-spring-data. – gawi Aug 12 '22 at 18:28
  • I already tried with `@Aggregation(pipeline = {"{'$match':{'typeOfAdventureHolidays':'trekking'}}", "{$sample:{size:1}}"})` on this way it return sometimes same element twice, I dont want that – Stefan Jankovic Aug 12 '22 at 18:30
  • If you know a way this is my problem. API controller on every refresh need to return one random element from collection, but never same document twice – Stefan Jankovic Aug 12 '22 at 18:31
  • So if I understandyou correctly when you have elements A,B,C in database in the first three calls A can appear only once, B only once and C only once? If so, then the only option is to fetch all of them, shuffle, store them in your app and return sequentially what you shuffled. Queries are stateless, so they don't depend on previous calls. – gawi Aug 12 '22 at 18:40
  • Yes, thats right. Can you help me with that? Can you post a answer of something that will be helpful to me? But also, I need to keep my criteria, program need to return me a docuemnts that have `typeOfAdventureHolidays` is `trekking` – Stefan Jankovic Aug 12 '22 at 18:41
  • I created method that count how many elements is in document, and I also set counter on API and if API calls counter is equals to number of elements in document I redirect user to the page that says no more elements, but my problem is as you said, A,B,C three API calls, always different element on return for every call – Stefan Jankovic Aug 12 '22 at 18:52
  • I just updated my answer. Let me know if this is what you wanted. Keep in mind that this should not be used on big data - fetching all elements from db into memory is usually bad idea – gawi Aug 12 '22 at 18:54
  • Hi, thanks, I'm trying to compile it but I have error warning on `return elementsToReturn.pop();` error is `Cannot resolve method 'pop' in 'Queue'`. – Stefan Jankovic Aug 12 '22 at 19:09
  • I tried to switch on List instead of Queue and then `return elementsToReturn.stream().findAny().orElse(null);` instead of `return elementsToReturn.pop();` and I get one random from database that is always different on app start but when I refresh page its same, I'm not getting new one – Stefan Jankovic Aug 12 '22 at 19:23
  • it should be poll not pop, sorry I don't use Java Queue interface too often... – gawi Aug 12 '22 at 19:57