spring-projects / spring-data-commons

Spring Data Commons. Interfaces and code shared between the various datastore specific implementations.
https://spring.io/projects/spring-data
Apache License 2.0
773 stars 672 forks source link

Scroll API - Example Code Problem and Question #3011

Closed hayscoder closed 9 months ago

hayscoder commented 9 months ago

The example code can be found here for the new Scroll API: https://github.com/spring-projects/spring-data-commons/wiki/Spring-Data-2023.0-%28Ullman%29-Release-Notes#scroll-api

However, the way that I am reading the code example, it seems to me that it would have an endless loop. If there are more than 20 records, then won't the second instantiation of "users" always result in the same item? It is going to the offset of the SIZE (in bold below) of the users object (should always result in 10 unless there is less than 20 items total) and then minus 1. So, won't it just keep getting the second result set over and over (objects 9-19 in an array)? Shouldn't it instead have a counter that is incremented by 10 each time it goes through the for loop?

Also, can anyone give an example where you use a MongoTemplate and a query object? We don't use the direct queries as the current example has and so I am wondering how you might use the feature with a MongoTemplate and a query object.

Thank you for the help!

Window<User> users = repository.findFirst10ByLastnameOrderByFirstname("Doe", ScrollPosition.offset());
do {

  for (User u : users) {
    // consume the user
  }

  // obtain the next Scroll
  users = repository.findFirst10ByLastnameOrderByFirstname("Doe", users.positionAt(**users.size()** - 1));
} while (!users.isEmpty() && users.hasNext());
mp911de commented 9 months ago

Scroll positions are denoted as "greater than ${position}". ScrollPosition.offset() usage translates to skip/limit.

You can find an example how to use ScrollPosition with a MongoDB query at

https://github.com/spring-projects/spring-data-mongodb/blob/05c38b819f3c8eedad8388d6c377e85a5db610ca/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateScrollTests.java#L124-L135

Let me know whether this helps.

hayscoder commented 9 months ago

That is EXTREMELY helpful! Thank you! Seems straightforward now but I was finding it difficult to find the right method heritage. So, essentially, just like sorting, we use the "with" method to add the scrolling type to the query. Very cool.

By looking at those examples, I could also see how I was misreading the example given in the release notes. It isn't really returning just the size of the item. users.positionAt(users.size() - 1) This piece of code in the example is actually going to return the Offset position of the last object in the window. So, that offset could be 10, 20, 30, 40, 50, etc. That is why it would work. I had misunderstood the code but viewing the extra test examples that you gave helped me a ton to sort out the confusion in my brain.

In final application, we won't scroll immediately to the next set. We would return one set back to the UI layer and then the user might ask for the next set. So, is it accurate that from the initial pull, we would want to send back to the UI not only the results but ALSO the serialized representation of the ScrollPosition object (especially for KeysetScrollPosition) so that when the user on the UI clicks "next" and the search method gets called on the backend that we can pass this ScrollPosition object back into that method and use it to scroll appropriately? Or is the necessary information to continue the scroll passed from one method execution to the next in some other fashion?

mp911de commented 9 months ago

You can serialize the ScrollPosition. Especially when using KeysetScrollPosition, make sure to capture the exact key types (map at KeysetScrollPosition.keys). While strings and numbers are easy to capture, more complex key types (dates) must be retained properly to resume your scrolling session.

I'm closing this ticket as it is resolved to me.