Skip to content

Commit 9ce8f90

Browse files
RUBY-3520 Sort option for updateOne and replaceOne (#2938)
1 parent 0ca7ed8 commit 9ce8f90

File tree

8 files changed

+409
-2
lines changed

8 files changed

+409
-2
lines changed

lib/mongo/bulk_write/transformable.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ module Transformable
9999
d['upsert'] = true if doc[:upsert]
100100
d[Operation::COLLATION] = doc[:collation] if doc[:collation]
101101
d['hint'] = doc[:hint] if doc[:hint]
102+
d['sort'] = doc[:sort] if doc[:sort]
102103
end
103104
}
104105

@@ -130,6 +131,7 @@ module Transformable
130131
d[Operation::COLLATION] = doc[:collation] if doc[:collation]
131132
d[Operation::ARRAY_FILTERS] = doc[:array_filters] if doc[:array_filters]
132133
d['hint'] = doc[:hint] if doc[:hint]
134+
d['sort'] = doc[:sort] if doc[:sort]
133135
end
134136
}
135137

lib/mongo/collection.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,11 @@ def parallel_scan(cursor_count, options = {})
10491049
# May be specified as a Hash (e.g. { _id: 1 }) or a String (e.g. "_id_").
10501050
# @option options [ Hash ] :let Mapping of variables to use in the command.
10511051
# See the server documentation for details.
1052+
# @option options [ Hash ] :sort Specifies which document the operation
1053+
# replaces if the query matches multiple documents. The first document
1054+
# matched by the sort order will be replaced.
1055+
# This option is only supported by servers >= 8.0. Older servers will
1056+
# report an error for using this option.
10521057
#
10531058
# @return [ Result ] The response from the database.
10541059
#
@@ -1115,6 +1120,11 @@ def update_many(filter, update, options = {})
11151120
# May be specified as a Hash (e.g. { _id: 1 }) or a String (e.g. "_id_").
11161121
# @option options [ Hash ] :let Mapping of variables to use in the command.
11171122
# See the server documentation for details.
1123+
# @option options [ Hash ] :sort Specifies which document the operation
1124+
# updates if the query matches multiple documents. The first document
1125+
# matched by the sort order will be updated.
1126+
# This option is only supported by servers >= 8.0. Older servers will
1127+
# report an error for using this option.
11181128
#
11191129
# @return [ Result ] The response from the database.
11201130
#

lib/mongo/collection/view/writable.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,11 @@ def delete_one(opts = {})
389389
# @option opts [ true, false ] :upsert Whether to upsert if the
390390
# document doesn't exist.
391391
# Can be :w => Integer, :fsync => Boolean, :j => Boolean.
392+
# @option opts [ Hash ] :sort Specifies which document the operation
393+
# replaces if the query matches multiple documents. The first document
394+
# matched by the sort order will be replaced.
395+
# This option is only supported by servers >= 8.0. Older servers will
396+
# report an error for using this option.
392397
#
393398
# @return [ Result ] The response from the database.
394399
#
@@ -410,6 +415,7 @@ def replace_one(replacement, opts = {})
410415
Operation::U => replacement,
411416
hint: opts[:hint],
412417
collation: opts[:collation] || opts['collation'] || collation,
418+
sort: opts[:sort] || opts['sort'],
413419
}.compact
414420
if opts[:upsert]
415421
update_doc['upsert'] = true
@@ -549,6 +555,11 @@ def update_many(spec, opts = {})
549555
# document doesn't exist.
550556
# @option opts [ Hash ] :write_concern The write concern options.
551557
# Can be :w => Integer, :fsync => Boolean, :j => Boolean.
558+
# @option opts [ Hash ] :sort Specifies which document the operation
559+
# updates if the query matches multiple documents. The first document
560+
# matched by the sort order will be updated.
561+
# This option is only supported by servers >= 8.0. Older servers will
562+
# report an error for using this option.
552563
#
553564
# @return [ Result ] The response from the database.
554565
#
@@ -570,6 +581,7 @@ def update_one(spec, opts = {})
570581
Operation::U => spec,
571582
hint: opts[:hint],
572583
collation: opts[:collation] || opts['collation'] || collation,
584+
sort: opts[:sort] || opts['sort'],
573585
}.compact
574586
if opts[:upsert]
575587
update_doc['upsert'] = true

spec/runners/unified/crud_operations.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ def update_one(op)
194194
hint: args.use('hint'),
195195
upsert: args.use('upsert'),
196196
timeout_ms: args.use('timeoutMS'),
197-
max_time_ms: args.use('maxTimeMS')
197+
max_time_ms: args.use('maxTimeMS'),
198+
sort: args.use('sort')
198199
}
199200
if session = args.use('session')
200201
opts[:session] = entities.get(:session, session)
@@ -228,7 +229,8 @@ def replace_one(op)
228229
let: args.use('let'),
229230
hint: args.use('hint'),
230231
timeout_ms: args.use('timeoutMS'),
231-
max_time_ms: args.use('maxTimeMS')
232+
max_time_ms: args.use('maxTimeMS'),
233+
sort: args.use('sort'),
232234
)
233235
end
234236
end
@@ -358,6 +360,9 @@ def convert_bulk_write_spec(spec)
358360
else
359361
raise NotImplementedError, "Unknown operation #{op}"
360362
end
363+
if %w[ updateOne replaceOne ].include?(op)
364+
out[:sort] = spec.use('sort') if spec.key?('sort')
365+
end
361366
unless spec.empty?
362367
raise NotImplementedError, "Unhandled keys: #{spec}"
363368
end
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
description: BulkWrite replaceOne-sort
2+
3+
schemaVersion: "1.0"
4+
5+
createEntities:
6+
- client:
7+
id: &client0 client0
8+
observeEvents: [ commandStartedEvent, commandSucceededEvent ]
9+
- database:
10+
id: &database0 database0
11+
client: *client0
12+
databaseName: &database0Name crud-tests
13+
- collection:
14+
id: &collection0 collection0
15+
database: *database0
16+
collectionName: &collection0Name coll0
17+
18+
initialData:
19+
- collectionName: *collection0Name
20+
databaseName: *database0Name
21+
documents:
22+
- { _id: 1, x: 11 }
23+
- { _id: 2, x: 22 }
24+
- { _id: 3, x: 33 }
25+
26+
tests:
27+
- description: BulkWrite replaceOne with sort option
28+
runOnRequirements:
29+
- minServerVersion: "8.0"
30+
operations:
31+
- object: *collection0
32+
name: bulkWrite
33+
arguments:
34+
requests:
35+
- replaceOne:
36+
filter: { _id: { $gt: 1 } }
37+
sort: { _id: -1 }
38+
replacement: { x: 1 }
39+
expectEvents:
40+
- client: *client0
41+
events:
42+
- commandStartedEvent:
43+
command:
44+
update: *collection0Name
45+
updates:
46+
- q: { _id: { $gt: 1 } }
47+
u: { x: 1 }
48+
sort: { _id: -1 }
49+
multi: { $$unsetOrMatches: false }
50+
upsert: { $$unsetOrMatches: false }
51+
- commandSucceededEvent:
52+
reply: { ok: 1, n: 1 }
53+
commandName: update
54+
outcome:
55+
- collectionName: *collection0Name
56+
databaseName: *database0Name
57+
documents:
58+
- { _id: 1, x: 11 }
59+
- { _id: 2, x: 22 }
60+
- { _id: 3, x: 1 }
61+
62+
- description: BulkWrite replaceOne with sort option unsupported (server-side error)
63+
runOnRequirements:
64+
- maxServerVersion: "7.99"
65+
operations:
66+
- object: *collection0
67+
name: bulkWrite
68+
arguments:
69+
requests:
70+
- replaceOne:
71+
filter: { _id: { $gt: 1 } }
72+
sort: { _id: -1 }
73+
replacement: { x: 1 }
74+
expectError:
75+
isClientError: false
76+
expectEvents:
77+
- client: *client0
78+
events:
79+
- commandStartedEvent:
80+
command:
81+
update: *collection0Name
82+
updates:
83+
- q: { _id: { $gt: 1 } }
84+
u: { x: 1 }
85+
sort: { _id: -1 }
86+
multi: { $$unsetOrMatches: false }
87+
upsert: { $$unsetOrMatches: false }
88+
outcome:
89+
- collectionName: *collection0Name
90+
databaseName: *database0Name
91+
documents:
92+
- { _id: 1, x: 11 }
93+
- { _id: 2, x: 22 }
94+
- { _id: 3, x: 33 }
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
description: BulkWrite updateOne-sort
2+
3+
schemaVersion: "1.0"
4+
5+
createEntities:
6+
- client:
7+
id: &client0 client0
8+
observeEvents: [ commandStartedEvent, commandSucceededEvent ]
9+
- database:
10+
id: &database0 database0
11+
client: *client0
12+
databaseName: &database0Name crud-tests
13+
- collection:
14+
id: &collection0 collection0
15+
database: *database0
16+
collectionName: &collection0Name coll0
17+
18+
initialData:
19+
- collectionName: *collection0Name
20+
databaseName: *database0Name
21+
documents:
22+
- { _id: 1, x: 11 }
23+
- { _id: 2, x: 22 }
24+
- { _id: 3, x: 33 }
25+
26+
tests:
27+
- description: BulkWrite updateOne with sort option
28+
runOnRequirements:
29+
- minServerVersion: "8.0"
30+
operations:
31+
- object: *collection0
32+
name: bulkWrite
33+
arguments:
34+
requests:
35+
- updateOne:
36+
filter: { _id: { $gt: 1 } }
37+
sort: { _id: -1 }
38+
update: [ $set: { x: 1 } ]
39+
expectEvents:
40+
- client: *client0
41+
events:
42+
- commandStartedEvent:
43+
command:
44+
update: *collection0Name
45+
updates:
46+
- q: { _id: { $gt: 1 } }
47+
u: [ $set: { x: 1 } ]
48+
sort: { _id: -1 }
49+
multi: { $$unsetOrMatches: false }
50+
upsert: { $$unsetOrMatches: false }
51+
- commandSucceededEvent:
52+
reply: { ok: 1, n: 1 }
53+
commandName: update
54+
outcome:
55+
- collectionName: *collection0Name
56+
databaseName: *database0Name
57+
documents:
58+
- { _id: 1, x: 11 }
59+
- { _id: 2, x: 22 }
60+
- { _id: 3, x: 1 }
61+
62+
- description: BulkWrite updateOne with sort option unsupported (server-side error)
63+
runOnRequirements:
64+
- maxServerVersion: "7.99"
65+
operations:
66+
- object: *collection0
67+
name: bulkWrite
68+
arguments:
69+
requests:
70+
- updateOne:
71+
filter: { _id: { $gt: 1 } }
72+
sort: { _id: -1 }
73+
update: [ $set: { x: 1 } ]
74+
expectError:
75+
isClientError: false
76+
expectEvents:
77+
- client: *client0
78+
events:
79+
- commandStartedEvent:
80+
command:
81+
update: *collection0Name
82+
updates:
83+
- q: { _id: { $gt: 1 } }
84+
u: [ $set: { x: 1 } ]
85+
sort: { _id: -1 }
86+
multi: { $$unsetOrMatches: false }
87+
upsert: { $$unsetOrMatches: false }
88+
outcome:
89+
- collectionName: *collection0Name
90+
databaseName: *database0Name
91+
documents:
92+
- { _id: 1, x: 11 }
93+
- { _id: 2, x: 22 }
94+
- { _id: 3, x: 33 }
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
description: replaceOne-sort
2+
3+
schemaVersion: "1.0"
4+
5+
createEntities:
6+
- client:
7+
id: &client0 client0
8+
observeEvents: [ commandStartedEvent, commandSucceededEvent ]
9+
- database:
10+
id: &database0 database0
11+
client: *client0
12+
databaseName: &database0Name crud-tests
13+
- collection:
14+
id: &collection0 collection0
15+
database: *database0
16+
collectionName: &collection0Name coll0
17+
18+
initialData:
19+
- collectionName: *collection0Name
20+
databaseName: *database0Name
21+
documents:
22+
- { _id: 1, x: 11 }
23+
- { _id: 2, x: 22 }
24+
- { _id: 3, x: 33 }
25+
26+
tests:
27+
- description: ReplaceOne with sort option
28+
runOnRequirements:
29+
- minServerVersion: "8.0"
30+
operations:
31+
- name: replaceOne
32+
object: *collection0
33+
arguments:
34+
filter: { _id: { $gt: 1 } }
35+
sort: { _id: -1 }
36+
replacement: { x: 1 }
37+
expectResult:
38+
matchedCount: 1
39+
modifiedCount: 1
40+
upsertedCount: 0
41+
expectEvents:
42+
- client: *client0
43+
events:
44+
- commandStartedEvent:
45+
command:
46+
update: *collection0Name
47+
updates:
48+
- q: { _id: { $gt: 1 } }
49+
u: { x: 1 }
50+
sort: { _id: -1 }
51+
multi: { $$unsetOrMatches: false }
52+
upsert: { $$unsetOrMatches: false }
53+
- commandSucceededEvent:
54+
reply: { ok: 1, n: 1 }
55+
commandName: update
56+
outcome:
57+
- collectionName: *collection0Name
58+
databaseName: *database0Name
59+
documents:
60+
- { _id: 1, x: 11 }
61+
- { _id: 2, x: 22 }
62+
- { _id: 3, x: 1 }
63+
64+
- description: replaceOne with sort option unsupported (server-side error)
65+
runOnRequirements:
66+
- maxServerVersion: "7.99"
67+
operations:
68+
- name: replaceOne
69+
object: *collection0
70+
arguments:
71+
filter: { _id: { $gt: 1 } }
72+
sort: { _id: -1 }
73+
replacement: { x: 1 }
74+
expectError:
75+
isClientError: false
76+
expectEvents:
77+
- client: *client0
78+
events:
79+
- commandStartedEvent:
80+
command:
81+
update: *collection0Name
82+
updates:
83+
- q: { _id: { $gt: 1 } }
84+
u: { x: 1 }
85+
sort: { _id: -1 }
86+
multi: { $$unsetOrMatches: false }
87+
upsert: { $$unsetOrMatches: false }
88+
outcome:
89+
- collectionName: *collection0Name
90+
databaseName: *database0Name
91+
documents:
92+
- { _id: 1, x: 11 }
93+
- { _id: 2, x: 22 }
94+
- { _id: 3, x: 33 }

0 commit comments

Comments
 (0)