Skip to content

Commit be9cbd1

Browse files
committed
Merge branch 'master' of github.com:mongodb/mongo-python-driver
2 parents 8395c8b + 6f4258c commit be9cbd1

21 files changed

+1979
-166
lines changed

THIRD-PARTY-NOTICES

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -38,36 +38,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3838
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3939
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4040
THE SOFTWARE.
41-
42-
2) License Notice for bson-stdint-win32.h
43-
-----------------------------------------
44-
45-
ISO C9x compliant stdint.h for Microsoft Visual Studio
46-
Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
47-
48-
Copyright (c) 2006-2013 Alexander Chemeris
49-
50-
Redistribution and use in source and binary forms, with or without
51-
modification, are permitted provided that the following conditions are met:
52-
53-
1. Redistributions of source code must retain the above copyright notice,
54-
this list of conditions and the following disclaimer.
55-
56-
2. Redistributions in binary form must reproduce the above copyright
57-
notice, this list of conditions and the following disclaimer in the
58-
documentation and/or other materials provided with the distribution.
59-
60-
3. Neither the name of the product nor the names of its contributors may
61-
be used to endorse or promote products derived from this software
62-
without specific prior written permission.
63-
64-
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
65-
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
66-
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
67-
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
68-
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
69-
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
70-
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
71-
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
72-
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
73-
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

doc/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ PyMongo 4.11 brings a number of changes including:
1919
until either connection succeeds or a server selection timeout error is raised.
2020
- Added :func:`repr` support to :class:`pymongo.operations.IndexModel`.
2121
- Added :func:`repr` support to :class:`pymongo.operations.SearchIndexModel`.
22+
- Added ``sort`` parameter to
23+
:meth:`~pymongo.collection.Collection.update_one`, :meth:`~pymongo.collection.Collection.replace_one`,
24+
:class:`~pymongo.operations.UpdateOne`, and
25+
:class:`~pymongo.operations.UpdateMany`,
2226

2327
Issues Resolved
2428
...............

pymongo/asynchronous/bulk.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ def __init__(
109109
self.uses_array_filters = False
110110
self.uses_hint_update = False
111111
self.uses_hint_delete = False
112+
self.uses_sort = False
112113
self.is_retryable = True
113114
self.retrying = False
114115
self.started_retryable_write = False
@@ -144,6 +145,7 @@ def add_update(
144145
collation: Optional[Mapping[str, Any]] = None,
145146
array_filters: Optional[list[Mapping[str, Any]]] = None,
146147
hint: Union[str, dict[str, Any], None] = None,
148+
sort: Optional[Mapping[str, Any]] = None,
147149
) -> None:
148150
"""Create an update document and add it to the list of ops."""
149151
validate_ok_for_update(update)
@@ -159,6 +161,9 @@ def add_update(
159161
if hint is not None:
160162
self.uses_hint_update = True
161163
cmd["hint"] = hint
164+
if sort is not None:
165+
self.uses_sort = True
166+
cmd["sort"] = sort
162167
if multi:
163168
# A bulk_write containing an update_many is not retryable.
164169
self.is_retryable = False
@@ -171,6 +176,7 @@ def add_replace(
171176
upsert: bool = False,
172177
collation: Optional[Mapping[str, Any]] = None,
173178
hint: Union[str, dict[str, Any], None] = None,
179+
sort: Optional[Mapping[str, Any]] = None,
174180
) -> None:
175181
"""Create a replace document and add it to the list of ops."""
176182
validate_ok_for_replace(replacement)
@@ -181,6 +187,9 @@ def add_replace(
181187
if hint is not None:
182188
self.uses_hint_update = True
183189
cmd["hint"] = hint
190+
if sort is not None:
191+
self.uses_sort = True
192+
cmd["sort"] = sort
184193
self.ops.append((_UPDATE, cmd))
185194

186195
def add_delete(
@@ -699,6 +708,10 @@ async def execute_no_results(
699708
raise ConfigurationError(
700709
"Must be connected to MongoDB 4.2+ to use hint on unacknowledged update commands."
701710
)
711+
if unack and self.uses_sort and conn.max_wire_version < 25:
712+
raise ConfigurationError(
713+
"Must be connected to MongoDB 8.0+ to use sort on unacknowledged update commands."
714+
)
702715
# Cannot have both unacknowledged writes and bypass document validation.
703716
if self.bypass_doc_val:
704717
raise OperationFailure(

pymongo/asynchronous/client_bulk.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def __init__(
118118
self.uses_array_filters = False
119119
self.uses_hint_update = False
120120
self.uses_hint_delete = False
121+
self.uses_sort = False
121122

122123
self.is_retryable = self.client.options.retry_writes
123124
self.retrying = False
@@ -148,6 +149,7 @@ def add_update(
148149
collation: Optional[Mapping[str, Any]] = None,
149150
array_filters: Optional[list[Mapping[str, Any]]] = None,
150151
hint: Union[str, dict[str, Any], None] = None,
152+
sort: Optional[Mapping[str, Any]] = None,
151153
) -> None:
152154
"""Create an update document and add it to the list of ops."""
153155
validate_ok_for_update(update)
@@ -169,6 +171,9 @@ def add_update(
169171
if collation is not None:
170172
self.uses_collation = True
171173
cmd["collation"] = collation
174+
if sort is not None:
175+
self.uses_sort = True
176+
cmd["sort"] = sort
172177
if multi:
173178
# A bulk_write containing an update_many is not retryable.
174179
self.is_retryable = False
@@ -184,6 +189,7 @@ def add_replace(
184189
upsert: Optional[bool] = None,
185190
collation: Optional[Mapping[str, Any]] = None,
186191
hint: Union[str, dict[str, Any], None] = None,
192+
sort: Optional[Mapping[str, Any]] = None,
187193
) -> None:
188194
"""Create a replace document and add it to the list of ops."""
189195
validate_ok_for_replace(replacement)
@@ -202,6 +208,9 @@ def add_replace(
202208
if collation is not None:
203209
self.uses_collation = True
204210
cmd["collation"] = collation
211+
if sort is not None:
212+
self.uses_sort = True
213+
cmd["sort"] = sort
205214
self.ops.append(("replace", cmd))
206215
self.namespaces.append(namespace)
207216
self.total_ops += 1

pymongo/asynchronous/collection.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@ async def _update(
993993
session: Optional[AsyncClientSession] = None,
994994
retryable_write: bool = False,
995995
let: Optional[Mapping[str, Any]] = None,
996+
sort: Optional[Mapping[str, Any]] = None,
996997
comment: Optional[Any] = None,
997998
) -> Optional[Mapping[str, Any]]:
998999
"""Internal update / replace helper."""
@@ -1024,6 +1025,14 @@ async def _update(
10241025
if not isinstance(hint, str):
10251026
hint = helpers_shared._index_document(hint)
10261027
update_doc["hint"] = hint
1028+
if sort is not None:
1029+
if not acknowledged and conn.max_wire_version < 25:
1030+
raise ConfigurationError(
1031+
"Must be connected to MongoDB 8.0+ to use sort on unacknowledged update commands."
1032+
)
1033+
common.validate_is_mapping("sort", sort)
1034+
update_doc["sort"] = sort
1035+
10271036
command = {"update": self.name, "ordered": ordered, "updates": [update_doc]}
10281037
if let is not None:
10291038
common.validate_is_mapping("let", let)
@@ -1079,6 +1088,7 @@ async def _update_retryable(
10791088
hint: Optional[_IndexKeyHint] = None,
10801089
session: Optional[AsyncClientSession] = None,
10811090
let: Optional[Mapping[str, Any]] = None,
1091+
sort: Optional[Mapping[str, Any]] = None,
10821092
comment: Optional[Any] = None,
10831093
) -> Optional[Mapping[str, Any]]:
10841094
"""Internal update / replace helper."""
@@ -1102,6 +1112,7 @@ async def _update(
11021112
session=session,
11031113
retryable_write=retryable_write,
11041114
let=let,
1115+
sort=sort,
11051116
comment=comment,
11061117
)
11071118

@@ -1122,6 +1133,7 @@ async def replace_one(
11221133
hint: Optional[_IndexKeyHint] = None,
11231134
session: Optional[AsyncClientSession] = None,
11241135
let: Optional[Mapping[str, Any]] = None,
1136+
sort: Optional[Mapping[str, Any]] = None,
11251137
comment: Optional[Any] = None,
11261138
) -> UpdateResult:
11271139
"""Replace a single document matching the filter.
@@ -1176,8 +1188,13 @@ async def replace_one(
11761188
aggregate expression context (e.g. "$$var").
11771189
:param comment: A user-provided comment to attach to this
11781190
command.
1191+
:param sort: Specify which document the operation updates if the query matches
1192+
multiple documents. The first document matched by the sort order will be updated.
1193+
This option is only supported on MongoDB 8.0 and above.
11791194
:return: - An instance of :class:`~pymongo.results.UpdateResult`.
11801195
1196+
.. versionchanged:: 4.11
1197+
Added ``sort`` parameter.
11811198
.. versionchanged:: 4.1
11821199
Added ``let`` parameter.
11831200
Added ``comment`` parameter.
@@ -1209,6 +1226,7 @@ async def replace_one(
12091226
hint=hint,
12101227
session=session,
12111228
let=let,
1229+
sort=sort,
12121230
comment=comment,
12131231
),
12141232
write_concern.acknowledged,
@@ -1225,6 +1243,7 @@ async def update_one(
12251243
hint: Optional[_IndexKeyHint] = None,
12261244
session: Optional[AsyncClientSession] = None,
12271245
let: Optional[Mapping[str, Any]] = None,
1246+
sort: Optional[Mapping[str, Any]] = None,
12281247
comment: Optional[Any] = None,
12291248
) -> UpdateResult:
12301249
"""Update a single document matching the filter.
@@ -1283,11 +1302,16 @@ async def update_one(
12831302
constant or closed expressions that do not reference document
12841303
fields. Parameters can then be accessed as variables in an
12851304
aggregate expression context (e.g. "$$var").
1305+
:param sort: Specify which document the operation updates if the query matches
1306+
multiple documents. The first document matched by the sort order will be updated.
1307+
This option is only supported on MongoDB 8.0 and above.
12861308
:param comment: A user-provided comment to attach to this
12871309
command.
12881310
12891311
:return: - An instance of :class:`~pymongo.results.UpdateResult`.
12901312
1313+
.. versionchanged:: 4.11
1314+
Added ``sort`` parameter.
12911315
.. versionchanged:: 4.1
12921316
Added ``let`` parameter.
12931317
Added ``comment`` parameter.
@@ -1322,6 +1346,7 @@ async def update_one(
13221346
hint=hint,
13231347
session=session,
13241348
let=let,
1349+
sort=sort,
13251350
comment=comment,
13261351
),
13271352
write_concern.acknowledged,

0 commit comments

Comments
 (0)