@@ -16,21 +16,37 @@ def scroll(cursor_or_type = nil, options = nil, &_block)
16
16
cursor_options = { field_name : scroll_field , direction : scroll_direction } . merge ( options )
17
17
cursor = cursor && cursor . is_a? ( cursor_type ) ? cursor : cursor_type . new ( cursor , cursor_options )
18
18
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
27
41
# scroll
28
42
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
31
47
end
32
48
else
33
- view
49
+ records
34
50
end
35
51
end
36
52
end
0 commit comments