Skip to content

Commit 089a518

Browse files
committed
keep the ordering when fetching previous records
1 parent 3ca3244 commit 089a518

File tree

3 files changed

+46
-29
lines changed

3 files changed

+46
-29
lines changed

lib/mongo/scrollable.rb

+27-11
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,37 @@ def scroll(cursor_or_type = nil, options = nil, &_block)
1616
cursor_options = { field_name: scroll_field, direction: scroll_direction }.merge(options)
1717
cursor = cursor && cursor.is_a?(cursor_type) ? cursor : cursor_type.new(cursor, cursor_options)
1818
raise_mismatched_sort_fields_error!(cursor, cursor_options) if different_sort_fields?(cursor, cursor_options)
19-
# make a view
20-
view = Mongo::Collection::View.new(
21-
view.collection,
22-
view.selector.merge(cursor.criteria),
23-
sort: (view.sort || {}).merge(_id: scroll_direction),
24-
skip: skip,
25-
limit: limit
26-
)
19+
20+
records = nil
21+
if cursor.previous && limit
22+
# scroll backards by reversing the sort order, limit and then reverse again
23+
pipeline = [
24+
{ '$match' => view.selector.merge(cursor.criteria) },
25+
{ '$sort' => { scroll_field => -scroll_direction } },
26+
{ '$limit' => limit },
27+
{ '$sort' => { scroll_field => scroll_direction } }
28+
]
29+
aggregation_options = view.options.except(:sort)
30+
records = view.aggregate(pipeline, aggregation_options)
31+
else
32+
# make a view
33+
records = Mongo::Collection::View.new(
34+
view.collection,
35+
view.selector.merge(cursor.criteria),
36+
sort: (view.sort || {}).merge(_id: scroll_direction),
37+
skip: skip,
38+
limit: limit
39+
)
40+
end
2741
# scroll
2842
if block_given?
29-
view.each do |record|
30-
yield record, cursor_type.from_record(record, cursor_options), cursor_type.from_record(record, cursor_options.merge(previous: true))
43+
previous_cursor = nil
44+
records.each do |record|
45+
previous_cursor ||= cursor_type.from_record(record, cursor_options.merge(previous: true))
46+
yield record, cursor_type.from_record(record, cursor_options), previous_cursor
3147
end
3248
else
33-
view
49+
records
3450
end
3551
end
3652
end

lib/mongoid/criteria/scrollable.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ def scroll(cursor_or_type = nil, &_block)
1414
raise_mismatched_sort_fields_error!(cursor, cursor_options) if different_sort_fields?(cursor, cursor_options)
1515
records = find_records(criteria, cursor)
1616
if block_given?
17-
first_cursor = cursor_from_record(cursor_type, records.first, cursor_options.merge(previous: true))
17+
previous_cursor = nil
1818
records.each do |record|
19-
yield record, cursor_from_record(cursor_type, record, cursor_options), first_cursor
19+
previous_cursor ||= cursor_from_record(cursor_type, record, cursor_options.merge(previous: true))
20+
yield record, cursor_from_record(cursor_type, record, cursor_options), previous_cursor
2021
end
2122
else
2223
records

spec/mongo/collection_view_spec.rb

+16-16
Original file line numberDiff line numberDiff line change
@@ -107,26 +107,26 @@
107107
expect(cursor.tiebreak_id).to eq record['_id']
108108
end
109109
it 'can scroll back with the previous cursor' do
110-
records = []
111-
first_cursor = nil
112-
second_cursor = nil
113-
third_cursor = nil
114-
criteria = Mongoid.default_client['feed_items'].find.limit(2)
115-
criteria.scroll(cursor_type) do |record, next_cursor|
116-
second_cursor = next_cursor
110+
cursor = nil
111+
first_previous_cursor = nil
112+
second_previous_cursor = nil
113+
114+
Mongoid.default_client['feed_items'].find.sort(field_name => 1).limit(2).scroll(cursor_type, field_type: field_type) do |_, next_cursor|
115+
cursor = next_cursor
117116
end
118-
criteria.scroll(second_cursor) do |record, next_cursor, previous_cursor|
119-
first_cursor = previous_cursor
120-
third_cursor = next_cursor
117+
118+
Mongoid.default_client['feed_items'].find.sort(field_name => 1).limit(2).scroll(cursor, field_type: field_type) do |_, next_cursor, previous_cursor|
119+
cursor = next_cursor
120+
first_previous_cursor = previous_cursor
121121
end
122122

123-
first_item = Mongoid.default_client['feed_items'].find.to_a[0]
124-
from_item = Mongoid.default_client['feed_items'].find.scroll(first_cursor).to_a.first
125-
expect(from_item).to eq first_item
123+
Mongoid.default_client['feed_items'].find.sort(field_name => 1).limit(2).scroll(cursor, field_type: field_type) do |_, _, previous_cursor|
124+
second_previous_cursor = previous_cursor
125+
end
126126

127-
fifth_item = Mongoid.default_client['feed_items'].find.to_a[4]
128-
from_item = Mongoid.default_client['feed_items'].find.scroll(third_cursor).to_a.first
129-
expect(from_item).to eq fifth_item
127+
records = Mongoid.default_client['feed_items'].find.sort(field_name => 1)
128+
expect(Mongoid.default_client['feed_items'].find.sort(field_name => 1).limit(2).scroll(first_previous_cursor, field_type: field_type).to_a).to eq(records.limit(2).to_a)
129+
expect(Mongoid.default_client['feed_items'].find.sort(field_name => 1).limit(2).scroll(second_previous_cursor, field_type: field_type).to_a).to eq(records.skip(2).limit(2).to_a)
130130
end
131131
end
132132
end

0 commit comments

Comments
 (0)