Skip to content

Add support for Keyset- and Offset-based cursor scrolling #4317

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from

Conversation

mp911de
Copy link
Member

@mp911de mp911de commented Mar 6, 2023

Usage examples:

Repository query methods

interface UserRepository extends Repository<User, Long> {

  Scroll<User> findFirst10ByLastnameOrderByFirstname(String lastname, OffsetScrollPosition position);
}

Scroll<User> users = repository.findFirst10ByLastnameOrderByFirstname("Doe", OffsetScrollPosition.initial());

do {

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

  // obtain the next Scroll
  users = repository.findFirst10ByLastnameOrderByFirstname("Doe", users.lastScrollPosition());
} while (!users.isEmpty() && !users.isLast());

Template API

MongoTemplate template = …;

Query q = new Query(where("firstName").regex("J.*"))
              .with(Sort.by("firstName", "age"))
              .limit(2)
              .with(KeysetScrollPosition.initial());

Scroll<Person> scroll = template.scroll(q, Person.class);

Scroll<Person> scroll = template.query(Person.class)
                               .matching(Query.query(where("firstName").regex("J.*"))
                                              .with(Sort.by("firstName", "age")))
                               .scroll(OffsetScrollPosition.of(10));

Tasks:

  • Implementation
  • Revisit Sort precedence and limit/skip relationship to CursorRequest for methods accepting Query and CursorRequest types
  • Documentation

Limitations:

  • Using projections with Keyset-scrolling requires all keyset properties to be present in the target projection type

Closes #4308
Depends on spring-projects/spring-data-commons#2787

@mp911de mp911de added the type: enhancement A general enhancement label Mar 6, 2023
@christophstrobl
Copy link
Member

Queries that either sort by or project on synthetic fields, such as { $meta: "textScore" }, cannot utilize keyset pagination.
Sorting by eg. { score: { $meta: "textScore" } } would need us to include the last seen score in the request for the next Window leading to something like {"$text": {"$search": "spring"}, "score" : {"$gt" : 0.5 }} which returns an empty result cause the stored documents do not contain a score field.
To support this feature we'd have to internally convert the Query into an Aggregation that uses a [$match, $project, $match] pipeline that runs the the raw query, additionally projects on the score and then matches against the score in the third stage. It would be good the get some input from MongoDB if they see value in this approach.


@Override
// TODO: CursorRequest and Query declare both a Sort. Which one has precedence?
// CursorRequest is similar to Pageable in the sense of being required to define a sort order
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That we have to ask ourselves this is an indicator that maybe the request should not be allowed to redefine sorting.

KeySetCursorQuery keysetPaginationQuery = CursorUtils.createKeysetPaginationQuery(query, keyset,
operations.getIdPropertyName(sourceClass));

List<T> result = doFind(collectionName, createDelegate(query), keysetPaginationQuery.query(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're ignoring the targetClass here. Might be worth to call doFind(createDelegate(query), collectionName, keysetPaginationQuery.query(), keysetPaginationQuery.fields(), sourceClass, targetClass, new QueryCursorPreparer(query, keysetPaginationQuery.sort(), limit, 0, sourceClass)); instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targetClass is considered in ReadDocumentCallback. We might want to switch to ProjectingReadCallback though. Same for the imperative template.

@christophstrobl
Copy link
Member

field projections using expressions work fine since those cannot be used for sorting.

q.fields().project(valueOf("firstName").length()).as("nameLength").include("firstName", "age");

@mp911de mp911de mentioned this pull request Mar 9, 2023
3 tasks
@mp911de mp911de changed the title Add support for Keyset- and Offset-based cursor windowing Add support for Keyset- and Offset-based cursor scrolling Mar 9, 2023
mp911de and others added 5 commits March 16, 2023 11:25
We now support scrolling through large query results using ScrollPosition and Window's of data.
Follow the changes in data commons that renamed scroll to window.
Also error when a certain scroll position does not allow creating a query out of it because of null values.
mp911de and others added 2 commits March 16, 2023 12:02
Along the lines fix entity operations proxy handling by reading the underlying map instead of inspecting the proxy interface.
Also make sure to map potential raw fields back to the according property.
christophstrobl pushed a commit that referenced this pull request Mar 17, 2023
We now support scrolling through large query results using ScrollPosition and Window's of data.

See: #4308
Original Pull Request: #4317
christophstrobl pushed a commit that referenced this pull request Mar 17, 2023
christophstrobl added a commit that referenced this pull request Mar 17, 2023
Follow the changes in data commons that renamed scroll to window.
Also error when a certain scroll position does not allow creating a query out of it because of null values.

See: #4308
Original Pull Request: #4317
christophstrobl pushed a commit that referenced this pull request Mar 17, 2023
Closes #4325
Related to: #4308
Original Pull Request: #4317
christophstrobl pushed a commit that referenced this pull request Mar 17, 2023
christophstrobl added a commit that referenced this pull request Mar 17, 2023
Along the lines fix entity operations proxy handling by reading the underlying map instead of inspecting the proxy interface.
Also make sure to map potential raw fields back to the according property.

See: #4308
Original Pull Request: #4317
@christophstrobl christophstrobl deleted the issue/4308 branch March 17, 2023 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for keyset scrolling
2 participants