Skip to content

Commit 3ca3244

Browse files
committed
keep the ordering when fetching previous records
1 parent 76287e8 commit 3ca3244

File tree

2 files changed

+31
-19
lines changed

2 files changed

+31
-19
lines changed

lib/mongoid/criteria/scrollable.rb

+18-9
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,15 @@ def scroll(cursor_or_type = nil, &_block)
1111
criteria.merge!(default_sort) if no_sort_option?
1212
cursor_options = build_cursor_options(criteria)
1313
cursor = cursor.is_a?(cursor_type) ? cursor : new_cursor(cursor_type, cursor, cursor_options)
14-
direction = scroll_direction(criteria)
1514
raise_mismatched_sort_fields_error!(cursor, cursor_options) if different_sort_fields?(cursor, cursor_options)
16-
cursor_criteria = build_cursor_criteria(criteria, cursor)
17-
first_in_page = nil
15+
records = find_records(criteria, cursor)
1816
if block_given?
19-
cursor_criteria.order_by(_id: direction).each do |record|
20-
first_in_page ||= record
21-
yield record, cursor_from_record(cursor_type, record, cursor_options), cursor_from_record(cursor_type, first_in_page, cursor_options.merge(previous: true))
17+
first_cursor = cursor_from_record(cursor_type, records.first, cursor_options.merge(previous: true))
18+
records.each do |record|
19+
yield record, cursor_from_record(cursor_type, record, cursor_options), first_cursor
2220
end
2321
else
24-
cursor_criteria
22+
records
2523
end
2624
end
2725

@@ -63,10 +61,21 @@ def new_cursor(cursor_type, cursor, cursor_options)
6361
cursor_type.new(cursor, cursor_options)
6462
end
6563

66-
def build_cursor_criteria(criteria, cursor)
64+
def find_records(criteria, cursor)
6765
cursor_criteria = criteria.dup
6866
cursor_criteria.selector = { '$and' => [criteria.selector, cursor.criteria] }
69-
cursor_criteria
67+
if cursor.previous && criteria.options[:limit]
68+
pipeline = [
69+
{ '$match' => cursor_criteria.selector },
70+
{ '$sort' => { cursor.field_name => -cursor.direction } },
71+
{ '$limit' => criteria.options[:limit] },
72+
{ '$sort' => { cursor.field_name => cursor.direction } }
73+
]
74+
aggregation = cursor_criteria.view.aggregate(pipeline)
75+
aggregation.map { Mongoid::Factory.from_db(cursor_criteria.klass, _1) }
76+
else
77+
cursor_criteria.order_by(_id: scroll_direction(criteria))
78+
end
7079
end
7180

7281
def cursor_from_record(cursor_type, record, cursor_options)

spec/mongoid/criteria_spec.rb

+13-10
Original file line numberDiff line numberDiff line change
@@ -161,23 +161,26 @@
161161
end
162162
end
163163
it 'can scroll back with the previous cursor' do
164-
first_cursor = nil
165-
second_cursor = nil
164+
cursor = nil
165+
first_previous_cursor = nil
166+
second_previous_cursor = nil
166167

167168
Feed::Item.asc(field_name).limit(2).scroll(cursor_type) do |_, next_cursor|
168-
second_cursor = next_cursor
169+
cursor = next_cursor
169170
end
170-
Feed::Item.asc(field_name).limit(2).scroll(second_cursor) do |_, _, previous_cursor|
171-
first_cursor = previous_cursor
171+
172+
Feed::Item.asc(field_name).limit(2).scroll(cursor) do |_, next_cursor, previous_cursor|
173+
cursor = next_cursor
174+
first_previous_cursor = previous_cursor
172175
end
173176

174-
records = []
175-
Feed::Item.asc(field_name).limit(2).scroll(first_cursor) do |record|
176-
records << record
177+
Feed::Item.asc(field_name).limit(2).scroll(cursor) do |_, _, previous_cursor|
178+
second_previous_cursor = previous_cursor
177179
end
178-
expect(records).to eq Feed::Item.asc(field_name).limit(2).to_a
179180

180-
expect(Feed::Item.asc(field_name).scroll(first_cursor).to_a).to eq Feed::Item.asc(field_name).limit(2).to_a
181+
records = Feed::Item.asc(field_name)
182+
expect(Feed::Item.asc(field_name).limit(2).scroll(first_previous_cursor)).to eq(records.limit(2))
183+
expect(Feed::Item.asc(field_name).limit(2).scroll(second_previous_cursor)).to eq(records.skip(2).limit(2))
181184
end
182185
end
183186
end

0 commit comments

Comments
 (0)