Merge branch 'master' of github.com:mongodb/mongo-python-driver

This commit is contained in:
Steven Silvester 2024-10-16 18:20:09 -05:00
commit be9cbd1397
No known key found for this signature in database
GPG Key ID: B1BF5EC3A8B32F91
21 changed files with 2060 additions and 247 deletions

View File

@ -38,36 +38,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
2) License Notice for bson-stdint-win32.h
-----------------------------------------
ISO C9x compliant stdint.h for Microsoft Visual Studio
Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
Copyright (c) 2006-2013 Alexander Chemeris
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the product nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -19,6 +19,10 @@ PyMongo 4.11 brings a number of changes including:
until either connection succeeds or a server selection timeout error is raised.
- Added :func:`repr` support to :class:`pymongo.operations.IndexModel`.
- Added :func:`repr` support to :class:`pymongo.operations.SearchIndexModel`.
- Added ``sort`` parameter to
:meth:`~pymongo.collection.Collection.update_one`, :meth:`~pymongo.collection.Collection.replace_one`,
:class:`~pymongo.operations.UpdateOne`, and
:class:`~pymongo.operations.UpdateMany`,
Issues Resolved
...............

View File

@ -109,6 +109,7 @@ class _AsyncBulk:
self.uses_array_filters = False
self.uses_hint_update = False
self.uses_hint_delete = False
self.uses_sort = False
self.is_retryable = True
self.retrying = False
self.started_retryable_write = False
@ -144,6 +145,7 @@ class _AsyncBulk:
collation: Optional[Mapping[str, Any]] = None,
array_filters: Optional[list[Mapping[str, Any]]] = None,
hint: Union[str, dict[str, Any], None] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Create an update document and add it to the list of ops."""
validate_ok_for_update(update)
@ -159,6 +161,9 @@ class _AsyncBulk:
if hint is not None:
self.uses_hint_update = True
cmd["hint"] = hint
if sort is not None:
self.uses_sort = True
cmd["sort"] = sort
if multi:
# A bulk_write containing an update_many is not retryable.
self.is_retryable = False
@ -171,6 +176,7 @@ class _AsyncBulk:
upsert: bool = False,
collation: Optional[Mapping[str, Any]] = None,
hint: Union[str, dict[str, Any], None] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Create a replace document and add it to the list of ops."""
validate_ok_for_replace(replacement)
@ -181,6 +187,9 @@ class _AsyncBulk:
if hint is not None:
self.uses_hint_update = True
cmd["hint"] = hint
if sort is not None:
self.uses_sort = True
cmd["sort"] = sort
self.ops.append((_UPDATE, cmd))
def add_delete(
@ -699,6 +708,10 @@ class _AsyncBulk:
raise ConfigurationError(
"Must be connected to MongoDB 4.2+ to use hint on unacknowledged update commands."
)
if unack and self.uses_sort and conn.max_wire_version < 25:
raise ConfigurationError(
"Must be connected to MongoDB 8.0+ to use sort on unacknowledged update commands."
)
# Cannot have both unacknowledged writes and bypass document validation.
if self.bypass_doc_val:
raise OperationFailure(

View File

@ -118,6 +118,7 @@ class _AsyncClientBulk:
self.uses_array_filters = False
self.uses_hint_update = False
self.uses_hint_delete = False
self.uses_sort = False
self.is_retryable = self.client.options.retry_writes
self.retrying = False
@ -148,6 +149,7 @@ class _AsyncClientBulk:
collation: Optional[Mapping[str, Any]] = None,
array_filters: Optional[list[Mapping[str, Any]]] = None,
hint: Union[str, dict[str, Any], None] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Create an update document and add it to the list of ops."""
validate_ok_for_update(update)
@ -169,6 +171,9 @@ class _AsyncClientBulk:
if collation is not None:
self.uses_collation = True
cmd["collation"] = collation
if sort is not None:
self.uses_sort = True
cmd["sort"] = sort
if multi:
# A bulk_write containing an update_many is not retryable.
self.is_retryable = False
@ -184,6 +189,7 @@ class _AsyncClientBulk:
upsert: Optional[bool] = None,
collation: Optional[Mapping[str, Any]] = None,
hint: Union[str, dict[str, Any], None] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Create a replace document and add it to the list of ops."""
validate_ok_for_replace(replacement)
@ -202,6 +208,9 @@ class _AsyncClientBulk:
if collation is not None:
self.uses_collation = True
cmd["collation"] = collation
if sort is not None:
self.uses_sort = True
cmd["sort"] = sort
self.ops.append(("replace", cmd))
self.namespaces.append(namespace)
self.total_ops += 1

View File

@ -993,6 +993,7 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
session: Optional[AsyncClientSession] = None,
retryable_write: bool = False,
let: Optional[Mapping[str, Any]] = None,
sort: Optional[Mapping[str, Any]] = None,
comment: Optional[Any] = None,
) -> Optional[Mapping[str, Any]]:
"""Internal update / replace helper."""
@ -1024,6 +1025,14 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
if not isinstance(hint, str):
hint = helpers_shared._index_document(hint)
update_doc["hint"] = hint
if sort is not None:
if not acknowledged and conn.max_wire_version < 25:
raise ConfigurationError(
"Must be connected to MongoDB 8.0+ to use sort on unacknowledged update commands."
)
common.validate_is_mapping("sort", sort)
update_doc["sort"] = sort
command = {"update": self.name, "ordered": ordered, "updates": [update_doc]}
if let is not None:
common.validate_is_mapping("let", let)
@ -1079,6 +1088,7 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
hint: Optional[_IndexKeyHint] = None,
session: Optional[AsyncClientSession] = None,
let: Optional[Mapping[str, Any]] = None,
sort: Optional[Mapping[str, Any]] = None,
comment: Optional[Any] = None,
) -> Optional[Mapping[str, Any]]:
"""Internal update / replace helper."""
@ -1102,6 +1112,7 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
session=session,
retryable_write=retryable_write,
let=let,
sort=sort,
comment=comment,
)
@ -1122,6 +1133,7 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
hint: Optional[_IndexKeyHint] = None,
session: Optional[AsyncClientSession] = None,
let: Optional[Mapping[str, Any]] = None,
sort: Optional[Mapping[str, Any]] = None,
comment: Optional[Any] = None,
) -> UpdateResult:
"""Replace a single document matching the filter.
@ -1176,8 +1188,13 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
aggregate expression context (e.g. "$$var").
:param comment: A user-provided comment to attach to this
command.
:param sort: Specify which document the operation updates if the query matches
multiple documents. The first document matched by the sort order will be updated.
This option is only supported on MongoDB 8.0 and above.
:return: - An instance of :class:`~pymongo.results.UpdateResult`.
.. versionchanged:: 4.11
Added ``sort`` parameter.
.. versionchanged:: 4.1
Added ``let`` parameter.
Added ``comment`` parameter.
@ -1209,6 +1226,7 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
hint=hint,
session=session,
let=let,
sort=sort,
comment=comment,
),
write_concern.acknowledged,
@ -1225,6 +1243,7 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
hint: Optional[_IndexKeyHint] = None,
session: Optional[AsyncClientSession] = None,
let: Optional[Mapping[str, Any]] = None,
sort: Optional[Mapping[str, Any]] = None,
comment: Optional[Any] = None,
) -> UpdateResult:
"""Update a single document matching the filter.
@ -1283,11 +1302,16 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
constant or closed expressions that do not reference document
fields. Parameters can then be accessed as variables in an
aggregate expression context (e.g. "$$var").
:param sort: Specify which document the operation updates if the query matches
multiple documents. The first document matched by the sort order will be updated.
This option is only supported on MongoDB 8.0 and above.
:param comment: A user-provided comment to attach to this
command.
:return: - An instance of :class:`~pymongo.results.UpdateResult`.
.. versionchanged:: 4.11
Added ``sort`` parameter.
.. versionchanged:: 4.1
Added ``let`` parameter.
Added ``comment`` parameter.
@ -1322,6 +1346,7 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]):
hint=hint,
session=session,
let=let,
sort=sort,
comment=comment,
),
write_concern.acknowledged,

View File

@ -325,6 +325,7 @@ class ReplaceOne(Generic[_DocumentType]):
"_collation",
"_hint",
"_namespace",
"_sort",
)
def __init__(
@ -335,6 +336,7 @@ class ReplaceOne(Generic[_DocumentType]):
collation: Optional[_CollationIn] = None,
hint: Optional[_IndexKeyHint] = None,
namespace: Optional[str] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Create a ReplaceOne instance.
@ -353,8 +355,12 @@ class ReplaceOne(Generic[_DocumentType]):
:meth:`~pymongo.asynchronous.collection.AsyncCollection.create_index` or :meth:`~pymongo.collection.Collection.create_index` (e.g.
``[('field', ASCENDING)]``). This option is only supported on
MongoDB 4.2 and above.
:param sort: Specify which document the operation updates if the query matches
multiple documents. The first document matched by the sort order will be updated.
:param namespace: (optional) The namespace in which to replace a document.
.. versionchanged:: 4.10
Added ``sort`` option.
.. versionchanged:: 4.9
Added the `namespace` option to support `MongoClient.bulk_write`.
.. versionchanged:: 3.11
@ -371,6 +377,7 @@ class ReplaceOne(Generic[_DocumentType]):
else:
self._hint = hint
self._sort = sort
self._filter = filter
self._doc = replacement
self._upsert = upsert
@ -385,6 +392,7 @@ class ReplaceOne(Generic[_DocumentType]):
self._upsert,
collation=validate_collation_or_none(self._collation),
hint=self._hint,
sort=self._sort,
)
def _add_to_client_bulk(self, bulkobj: _AgnosticClientBulk) -> None:
@ -400,6 +408,7 @@ class ReplaceOne(Generic[_DocumentType]):
self._upsert,
collation=validate_collation_or_none(self._collation),
hint=self._hint,
sort=self._sort,
)
def __eq__(self, other: Any) -> bool:
@ -411,99 +420,15 @@ class ReplaceOne(Generic[_DocumentType]):
other._collation,
other._hint,
other._namespace,
other._sort,
) == (
self._filter,
self._doc,
self._upsert,
self._collation,
other._hint,
self._namespace,
)
return NotImplemented
def __ne__(self, other: Any) -> bool:
return not self == other
def __repr__(self) -> str:
if self._namespace:
return "{}({!r}, {!r}, {!r}, {!r}, {!r}, {!r})".format(
self.__class__.__name__,
self._filter,
self._doc,
self._upsert,
self._collation,
self._hint,
self._namespace,
)
return "{}({!r}, {!r}, {!r}, {!r}, {!r})".format(
self.__class__.__name__,
self._filter,
self._doc,
self._upsert,
self._collation,
self._hint,
)
class _UpdateOp:
"""Private base class for update operations."""
__slots__ = (
"_filter",
"_doc",
"_upsert",
"_collation",
"_array_filters",
"_hint",
"_namespace",
)
def __init__(
self,
filter: Mapping[str, Any],
doc: Union[Mapping[str, Any], _Pipeline],
upsert: Optional[bool],
collation: Optional[_CollationIn],
array_filters: Optional[list[Mapping[str, Any]]],
hint: Optional[_IndexKeyHint],
namespace: Optional[str],
):
if filter is not None:
validate_is_mapping("filter", filter)
if upsert is not None:
validate_boolean("upsert", upsert)
if array_filters is not None:
validate_list("array_filters", array_filters)
if hint is not None and not isinstance(hint, str):
self._hint: Union[str, dict[str, Any], None] = helpers_shared._index_document(hint)
else:
self._hint = hint
self._filter = filter
self._doc = doc
self._upsert = upsert
self._collation = collation
self._array_filters = array_filters
self._namespace = namespace
def __eq__(self, other: object) -> bool:
if isinstance(other, type(self)):
return (
other._filter,
other._doc,
other._upsert,
other._collation,
other._array_filters,
other._hint,
other._namespace,
) == (
self._filter,
self._doc,
self._upsert,
self._collation,
self._array_filters,
self._hint,
self._namespace,
self._sort,
)
return NotImplemented
@ -518,11 +443,104 @@ class _UpdateOp:
self._doc,
self._upsert,
self._collation,
self._array_filters,
self._hint,
self._namespace,
self._sort,
)
return "{}({!r}, {!r}, {!r}, {!r}, {!r}, {!r})".format(
self.__class__.__name__,
self._filter,
self._doc,
self._upsert,
self._collation,
self._hint,
self._sort,
)
class _UpdateOp:
"""Private base class for update operations."""
__slots__ = (
"_filter",
"_doc",
"_upsert",
"_collation",
"_array_filters",
"_hint",
"_namespace",
"_sort",
)
def __init__(
self,
filter: Mapping[str, Any],
doc: Union[Mapping[str, Any], _Pipeline],
upsert: Optional[bool],
collation: Optional[_CollationIn],
array_filters: Optional[list[Mapping[str, Any]]],
hint: Optional[_IndexKeyHint],
namespace: Optional[str],
sort: Optional[Mapping[str, Any]],
):
if filter is not None:
validate_is_mapping("filter", filter)
if upsert is not None:
validate_boolean("upsert", upsert)
if array_filters is not None:
validate_list("array_filters", array_filters)
if hint is not None and not isinstance(hint, str):
self._hint: Union[str, dict[str, Any], None] = helpers_shared._index_document(hint)
else:
self._hint = hint
self._filter = filter
self._doc = doc
self._upsert = upsert
self._collation = collation
self._array_filters = array_filters
self._namespace = namespace
self._sort = sort
def __eq__(self, other: object) -> bool:
if isinstance(other, type(self)):
return (
other._filter,
other._doc,
other._upsert,
other._collation,
other._array_filters,
other._hint,
other._namespace,
other._sort,
) == (
self._filter,
self._doc,
self._upsert,
self._collation,
self._array_filters,
self._hint,
self._namespace,
self._sort,
)
return NotImplemented
def __ne__(self, other: Any) -> bool:
return not self == other
def __repr__(self) -> str:
if self._namespace:
return "{}({!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r})".format(
self.__class__.__name__,
self._filter,
self._doc,
self._upsert,
self._collation,
self._array_filters,
self._hint,
self._namespace,
self._sort,
)
return "{}({!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r})".format(
self.__class__.__name__,
self._filter,
self._doc,
@ -530,6 +548,7 @@ class _UpdateOp:
self._collation,
self._array_filters,
self._hint,
self._sort,
)
@ -547,6 +566,7 @@ class UpdateOne(_UpdateOp):
array_filters: Optional[list[Mapping[str, Any]]] = None,
hint: Optional[_IndexKeyHint] = None,
namespace: Optional[str] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Represents an update_one operation.
@ -567,8 +587,12 @@ class UpdateOne(_UpdateOp):
:meth:`~pymongo.asynchronous.collection.AsyncCollection.create_index` or :meth:`~pymongo.collection.Collection.create_index` (e.g.
``[('field', ASCENDING)]``). This option is only supported on
MongoDB 4.2 and above.
:param namespace: (optional) The namespace in which to update a document.
:param namespace: The namespace in which to update a document.
:param sort: Specify which document the operation updates if the query matches
multiple documents. The first document matched by the sort order will be updated.
.. versionchanged:: 4.10
Added ``sort`` option.
.. versionchanged:: 4.9
Added the `namespace` option to support `MongoClient.bulk_write`.
.. versionchanged:: 3.11
@ -580,7 +604,7 @@ class UpdateOne(_UpdateOp):
.. versionchanged:: 3.5
Added the `collation` option.
"""
super().__init__(filter, update, upsert, collation, array_filters, hint, namespace)
super().__init__(filter, update, upsert, collation, array_filters, hint, namespace, sort)
def _add_to_bulk(self, bulkobj: _AgnosticBulk) -> None:
"""Add this operation to the _AsyncBulk/_Bulk instance `bulkobj`."""
@ -592,6 +616,7 @@ class UpdateOne(_UpdateOp):
collation=validate_collation_or_none(self._collation),
array_filters=self._array_filters,
hint=self._hint,
sort=self._sort,
)
def _add_to_client_bulk(self, bulkobj: _AgnosticClientBulk) -> None:
@ -609,6 +634,7 @@ class UpdateOne(_UpdateOp):
collation=validate_collation_or_none(self._collation),
array_filters=self._array_filters,
hint=self._hint,
sort=self._sort,
)
@ -659,7 +685,7 @@ class UpdateMany(_UpdateOp):
.. versionchanged:: 3.5
Added the `collation` option.
"""
super().__init__(filter, update, upsert, collation, array_filters, hint, namespace)
super().__init__(filter, update, upsert, collation, array_filters, hint, namespace, None)
def _add_to_bulk(self, bulkobj: _AgnosticBulk) -> None:
"""Add this operation to the _AsyncBulk/_Bulk instance `bulkobj`."""

View File

@ -109,6 +109,7 @@ class _Bulk:
self.uses_array_filters = False
self.uses_hint_update = False
self.uses_hint_delete = False
self.uses_sort = False
self.is_retryable = True
self.retrying = False
self.started_retryable_write = False
@ -144,6 +145,7 @@ class _Bulk:
collation: Optional[Mapping[str, Any]] = None,
array_filters: Optional[list[Mapping[str, Any]]] = None,
hint: Union[str, dict[str, Any], None] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Create an update document and add it to the list of ops."""
validate_ok_for_update(update)
@ -159,6 +161,9 @@ class _Bulk:
if hint is not None:
self.uses_hint_update = True
cmd["hint"] = hint
if sort is not None:
self.uses_sort = True
cmd["sort"] = sort
if multi:
# A bulk_write containing an update_many is not retryable.
self.is_retryable = False
@ -171,6 +176,7 @@ class _Bulk:
upsert: bool = False,
collation: Optional[Mapping[str, Any]] = None,
hint: Union[str, dict[str, Any], None] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Create a replace document and add it to the list of ops."""
validate_ok_for_replace(replacement)
@ -181,6 +187,9 @@ class _Bulk:
if hint is not None:
self.uses_hint_update = True
cmd["hint"] = hint
if sort is not None:
self.uses_sort = True
cmd["sort"] = sort
self.ops.append((_UPDATE, cmd))
def add_delete(
@ -697,6 +706,10 @@ class _Bulk:
raise ConfigurationError(
"Must be connected to MongoDB 4.2+ to use hint on unacknowledged update commands."
)
if unack and self.uses_sort and conn.max_wire_version < 25:
raise ConfigurationError(
"Must be connected to MongoDB 8.0+ to use sort on unacknowledged update commands."
)
# Cannot have both unacknowledged writes and bypass document validation.
if self.bypass_doc_val:
raise OperationFailure(

View File

@ -118,6 +118,7 @@ class _ClientBulk:
self.uses_array_filters = False
self.uses_hint_update = False
self.uses_hint_delete = False
self.uses_sort = False
self.is_retryable = self.client.options.retry_writes
self.retrying = False
@ -148,6 +149,7 @@ class _ClientBulk:
collation: Optional[Mapping[str, Any]] = None,
array_filters: Optional[list[Mapping[str, Any]]] = None,
hint: Union[str, dict[str, Any], None] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Create an update document and add it to the list of ops."""
validate_ok_for_update(update)
@ -169,6 +171,9 @@ class _ClientBulk:
if collation is not None:
self.uses_collation = True
cmd["collation"] = collation
if sort is not None:
self.uses_sort = True
cmd["sort"] = sort
if multi:
# A bulk_write containing an update_many is not retryable.
self.is_retryable = False
@ -184,6 +189,7 @@ class _ClientBulk:
upsert: Optional[bool] = None,
collation: Optional[Mapping[str, Any]] = None,
hint: Union[str, dict[str, Any], None] = None,
sort: Optional[Mapping[str, Any]] = None,
) -> None:
"""Create a replace document and add it to the list of ops."""
validate_ok_for_replace(replacement)
@ -202,6 +208,9 @@ class _ClientBulk:
if collation is not None:
self.uses_collation = True
cmd["collation"] = collation
if sort is not None:
self.uses_sort = True
cmd["sort"] = sort
self.ops.append(("replace", cmd))
self.namespaces.append(namespace)
self.total_ops += 1

View File

@ -992,6 +992,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
session: Optional[ClientSession] = None,
retryable_write: bool = False,
let: Optional[Mapping[str, Any]] = None,
sort: Optional[Mapping[str, Any]] = None,
comment: Optional[Any] = None,
) -> Optional[Mapping[str, Any]]:
"""Internal update / replace helper."""
@ -1023,6 +1024,14 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
if not isinstance(hint, str):
hint = helpers_shared._index_document(hint)
update_doc["hint"] = hint
if sort is not None:
if not acknowledged and conn.max_wire_version < 25:
raise ConfigurationError(
"Must be connected to MongoDB 8.0+ to use sort on unacknowledged update commands."
)
common.validate_is_mapping("sort", sort)
update_doc["sort"] = sort
command = {"update": self.name, "ordered": ordered, "updates": [update_doc]}
if let is not None:
common.validate_is_mapping("let", let)
@ -1078,6 +1087,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
hint: Optional[_IndexKeyHint] = None,
session: Optional[ClientSession] = None,
let: Optional[Mapping[str, Any]] = None,
sort: Optional[Mapping[str, Any]] = None,
comment: Optional[Any] = None,
) -> Optional[Mapping[str, Any]]:
"""Internal update / replace helper."""
@ -1101,6 +1111,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
session=session,
retryable_write=retryable_write,
let=let,
sort=sort,
comment=comment,
)
@ -1121,6 +1132,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
hint: Optional[_IndexKeyHint] = None,
session: Optional[ClientSession] = None,
let: Optional[Mapping[str, Any]] = None,
sort: Optional[Mapping[str, Any]] = None,
comment: Optional[Any] = None,
) -> UpdateResult:
"""Replace a single document matching the filter.
@ -1175,8 +1187,13 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
aggregate expression context (e.g. "$$var").
:param comment: A user-provided comment to attach to this
command.
:param sort: Specify which document the operation updates if the query matches
multiple documents. The first document matched by the sort order will be updated.
This option is only supported on MongoDB 8.0 and above.
:return: - An instance of :class:`~pymongo.results.UpdateResult`.
.. versionchanged:: 4.11
Added ``sort`` parameter.
.. versionchanged:: 4.1
Added ``let`` parameter.
Added ``comment`` parameter.
@ -1208,6 +1225,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
hint=hint,
session=session,
let=let,
sort=sort,
comment=comment,
),
write_concern.acknowledged,
@ -1224,6 +1242,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
hint: Optional[_IndexKeyHint] = None,
session: Optional[ClientSession] = None,
let: Optional[Mapping[str, Any]] = None,
sort: Optional[Mapping[str, Any]] = None,
comment: Optional[Any] = None,
) -> UpdateResult:
"""Update a single document matching the filter.
@ -1282,11 +1301,16 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
constant or closed expressions that do not reference document
fields. Parameters can then be accessed as variables in an
aggregate expression context (e.g. "$$var").
:param sort: Specify which document the operation updates if the query matches
multiple documents. The first document matched by the sort order will be updated.
This option is only supported on MongoDB 8.0 and above.
:param comment: A user-provided comment to attach to this
command.
:return: - An instance of :class:`~pymongo.results.UpdateResult`.
.. versionchanged:: 4.11
Added ``sort`` parameter.
.. versionchanged:: 4.1
Added ``let`` parameter.
Added ``comment`` parameter.
@ -1321,6 +1345,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
hint=hint,
session=session,
let=let,
sort=sort,
comment=comment,
),
write_concern.acknowledged,

View File

@ -971,6 +971,9 @@ class AsyncTestBulkWriteConcern(AsyncBulkTestBase):
@async_client_context.require_replica_set
@async_client_context.require_secondaries_count(1)
async def test_write_concern_failure_ordered(self):
self.skipTest("Skipping until PYTHON-4865 is resolved.")
details = None
# Ensure we don't raise on wnote.
coll_ww = self.coll.with_options(write_concern=WriteConcern(w=self.w))
result = await coll_ww.bulk_write([DeleteOne({"something": "that does no exist"})])
@ -1051,6 +1054,9 @@ class AsyncTestBulkWriteConcern(AsyncBulkTestBase):
@async_client_context.require_replica_set
@async_client_context.require_secondaries_count(1)
async def test_write_concern_failure_unordered(self):
self.skipTest("Skipping until PYTHON-4865 is resolved.")
details = None
# Ensure we don't raise on wnote.
coll_ww = self.coll.with_options(write_concern=WriteConcern(w=self.w))
result = await coll_ww.bulk_write(

View File

@ -78,11 +78,6 @@
"x": 33
}
]
},
{
"collectionName": "coll1",
"databaseName": "db0",
"documents": []
}
],
"tests": [
@ -159,22 +154,6 @@
}
]
}
],
"outcome": [
{
"collectionName": "coll1",
"databaseName": "db0",
"documents": [
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
]
},
{
@ -250,22 +229,6 @@
}
]
}
],
"outcome": [
{
"collectionName": "coll1",
"databaseName": "db0",
"documents": [
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
]
},
{
@ -344,22 +307,6 @@
}
]
}
],
"outcome": [
{
"collectionName": "coll1",
"databaseName": "db0",
"documents": [
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
]
},
{
@ -438,22 +385,6 @@
}
]
}
],
"outcome": [
{
"collectionName": "coll1",
"databaseName": "db0",
"documents": [
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
]
}
]

View File

@ -0,0 +1,239 @@
{
"description": "BulkWrite replaceOne-sort",
"schemaVersion": "1.0",
"createEntities": [
{
"client": {
"id": "client0",
"observeEvents": [
"commandStartedEvent",
"commandSucceededEvent"
]
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "crud-tests"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "coll0"
}
}
],
"initialData": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
],
"tests": [
{
"description": "BulkWrite replaceOne with sort option",
"runOnRequirements": [
{
"minServerVersion": "8.0"
}
],
"operations": [
{
"object": "collection0",
"name": "bulkWrite",
"arguments": {
"requests": [
{
"replaceOne": {
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"replacement": {
"x": 1
}
}
}
]
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"update": "coll0",
"updates": [
{
"q": {
"_id": {
"$gt": 1
}
},
"u": {
"x": 1
},
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
]
}
}
},
{
"commandSucceededEvent": {
"reply": {
"ok": 1,
"n": 1
},
"commandName": "update"
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 1
}
]
}
]
},
{
"description": "BulkWrite replaceOne with sort option unsupported (server-side error)",
"runOnRequirements": [
{
"maxServerVersion": "7.99"
}
],
"operations": [
{
"object": "collection0",
"name": "bulkWrite",
"arguments": {
"requests": [
{
"replaceOne": {
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"replacement": {
"x": 1
}
}
}
]
},
"expectError": {
"isClientError": false
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"update": "coll0",
"updates": [
{
"q": {
"_id": {
"$gt": 1
}
},
"u": {
"x": 1
},
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
]
}
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
]
}
]
}

View File

@ -0,0 +1,255 @@
{
"description": "BulkWrite updateOne-sort",
"schemaVersion": "1.0",
"createEntities": [
{
"client": {
"id": "client0",
"observeEvents": [
"commandStartedEvent",
"commandSucceededEvent"
]
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "crud-tests"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "coll0"
}
}
],
"initialData": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
],
"tests": [
{
"description": "BulkWrite updateOne with sort option",
"runOnRequirements": [
{
"minServerVersion": "8.0"
}
],
"operations": [
{
"object": "collection0",
"name": "bulkWrite",
"arguments": {
"requests": [
{
"updateOne": {
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"update": [
{
"$set": {
"x": 1
}
}
]
}
}
]
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"update": "coll0",
"updates": [
{
"q": {
"_id": {
"$gt": 1
}
},
"u": [
{
"$set": {
"x": 1
}
}
],
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
]
}
}
},
{
"commandSucceededEvent": {
"reply": {
"ok": 1,
"n": 1
},
"commandName": "update"
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 1
}
]
}
]
},
{
"description": "BulkWrite updateOne with sort option unsupported (server-side error)",
"runOnRequirements": [
{
"maxServerVersion": "7.99"
}
],
"operations": [
{
"object": "collection0",
"name": "bulkWrite",
"arguments": {
"requests": [
{
"updateOne": {
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"update": [
{
"$set": {
"x": 1
}
}
]
}
}
]
},
"expectError": {
"isClientError": false
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"update": "coll0",
"updates": [
{
"q": {
"_id": {
"$gt": 1
}
},
"u": [
{
"$set": {
"x": 1
}
}
],
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
]
}
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
]
}
]
}

View File

@ -0,0 +1,540 @@
{
"description": "client bulkWrite partial results",
"schemaVersion": "1.4",
"runOnRequirements": [
{
"minServerVersion": "8.0",
"serverless": "forbid"
}
],
"createEntities": [
{
"client": {
"id": "client0"
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "crud-tests"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "coll0"
}
}
],
"initialData": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
}
]
}
],
"_yamlAnchors": {
"namespace": "crud-tests.coll0",
"newDocument": {
"_id": 2,
"x": 22
}
},
"tests": [
{
"description": "partialResult is unset when first operation fails during an ordered bulk write (verbose)",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
},
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 2,
"x": 22
}
}
}
],
"ordered": true,
"verboseResults": true
},
"expectError": {
"expectResult": {
"$$unsetOrMatches": {
"insertedCount": {
"$$exists": false
},
"upsertedCount": {
"$$exists": false
},
"matchedCount": {
"$$exists": false
},
"modifiedCount": {
"$$exists": false
},
"deletedCount": {
"$$exists": false
},
"insertResults": {
"$$exists": false
},
"updateResults": {
"$$exists": false
},
"deleteResults": {
"$$exists": false
}
}
}
}
}
]
},
{
"description": "partialResult is unset when first operation fails during an ordered bulk write (summary)",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
},
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 2,
"x": 22
}
}
}
],
"ordered": true,
"verboseResults": false
},
"expectError": {
"expectResult": {
"$$unsetOrMatches": {
"insertedCount": {
"$$exists": false
},
"upsertedCount": {
"$$exists": false
},
"matchedCount": {
"$$exists": false
},
"modifiedCount": {
"$$exists": false
},
"deletedCount": {
"$$exists": false
},
"insertResults": {
"$$exists": false
},
"updateResults": {
"$$exists": false
},
"deleteResults": {
"$$exists": false
}
}
}
}
}
]
},
{
"description": "partialResult is set when second operation fails during an ordered bulk write (verbose)",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 2,
"x": 22
}
}
},
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
}
],
"ordered": true,
"verboseResults": true
},
"expectError": {
"expectResult": {
"insertedCount": 1,
"upsertedCount": 0,
"matchedCount": 0,
"modifiedCount": 0,
"deletedCount": 0,
"insertResults": {
"0": {
"insertedId": 2
}
},
"updateResults": {},
"deleteResults": {}
}
}
}
]
},
{
"description": "partialResult is set when second operation fails during an ordered bulk write (summary)",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 2,
"x": 22
}
}
},
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
}
],
"ordered": true,
"verboseResults": false
},
"expectError": {
"expectResult": {
"insertedCount": 1,
"upsertedCount": 0,
"matchedCount": 0,
"modifiedCount": 0,
"deletedCount": 0,
"insertResults": {
"$$unsetOrMatches": {}
},
"updateResults": {
"$$unsetOrMatches": {}
},
"deleteResults": {
"$$unsetOrMatches": {}
}
}
}
}
]
},
{
"description": "partialResult is unset when all operations fail during an unordered bulk write",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
},
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
}
],
"ordered": false
},
"expectError": {
"expectResult": {
"$$unsetOrMatches": {
"insertedCount": {
"$$exists": false
},
"upsertedCount": {
"$$exists": false
},
"matchedCount": {
"$$exists": false
},
"modifiedCount": {
"$$exists": false
},
"deletedCount": {
"$$exists": false
},
"insertResults": {
"$$exists": false
},
"updateResults": {
"$$exists": false
},
"deleteResults": {
"$$exists": false
}
}
}
}
}
]
},
{
"description": "partialResult is set when first operation fails during an unordered bulk write (verbose)",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
},
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 2,
"x": 22
}
}
}
],
"ordered": false,
"verboseResults": true
},
"expectError": {
"expectResult": {
"insertedCount": 1,
"upsertedCount": 0,
"matchedCount": 0,
"modifiedCount": 0,
"deletedCount": 0,
"insertResults": {
"1": {
"insertedId": 2
}
},
"updateResults": {},
"deleteResults": {}
}
}
}
]
},
{
"description": "partialResult is set when first operation fails during an unordered bulk write (summary)",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
},
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 2,
"x": 22
}
}
}
],
"ordered": false,
"verboseResults": false
},
"expectError": {
"expectResult": {
"insertedCount": 1,
"upsertedCount": 0,
"matchedCount": 0,
"modifiedCount": 0,
"deletedCount": 0,
"insertResults": {
"$$unsetOrMatches": {}
},
"updateResults": {
"$$unsetOrMatches": {}
},
"deleteResults": {
"$$unsetOrMatches": {}
}
}
}
}
]
},
{
"description": "partialResult is set when second operation fails during an unordered bulk write (verbose)",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 2,
"x": 22
}
}
},
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
}
],
"ordered": false,
"verboseResults": true
},
"expectError": {
"expectResult": {
"insertedCount": 1,
"upsertedCount": 0,
"matchedCount": 0,
"modifiedCount": 0,
"deletedCount": 0,
"insertResults": {
"0": {
"insertedId": 2
}
},
"updateResults": {},
"deleteResults": {}
}
}
}
]
},
{
"description": "partialResult is set when first operation fails during an unordered bulk write (summary)",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 2,
"x": 22
}
}
},
{
"insertOne": {
"namespace": "crud-tests.coll0",
"document": {
"_id": 1,
"x": 11
}
}
}
],
"ordered": false,
"verboseResults": false
},
"expectError": {
"expectResult": {
"insertedCount": 1,
"upsertedCount": 0,
"matchedCount": 0,
"modifiedCount": 0,
"deletedCount": 0,
"insertResults": {
"$$unsetOrMatches": {}
},
"updateResults": {
"$$unsetOrMatches": {}
},
"deleteResults": {
"$$unsetOrMatches": {}
}
}
}
}
]
}
]
}

View File

@ -0,0 +1,162 @@
{
"description": "client bulkWrite updateOne-sort",
"schemaVersion": "1.4",
"runOnRequirements": [
{
"minServerVersion": "8.0"
}
],
"createEntities": [
{
"client": {
"id": "client0",
"observeEvents": [
"commandStartedEvent",
"commandSucceededEvent"
]
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "crud-tests"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "coll0"
}
}
],
"initialData": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
],
"_yamlAnchors": {
"namespace": "crud-tests.coll0"
},
"tests": [
{
"description": "client bulkWrite replaceOne with sort option",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"replaceOne": {
"namespace": "crud-tests.coll0",
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"replacement": {
"x": 1
}
}
}
]
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"commandName": "bulkWrite",
"databaseName": "admin",
"command": {
"bulkWrite": 1,
"ops": [
{
"update": 0,
"filter": {
"_id": {
"$gt": 1
}
},
"updateMods": {
"x": 1
},
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
],
"nsInfo": [
{
"ns": "crud-tests.coll0"
}
]
}
}
},
{
"commandSucceededEvent": {
"reply": {
"ok": 1,
"nErrors": 0,
"nMatched": 1,
"nModified": 1
},
"commandName": "bulkWrite"
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 1
}
]
}
]
}
]
}

View File

@ -0,0 +1,166 @@
{
"description": "client bulkWrite updateOne-sort",
"schemaVersion": "1.4",
"runOnRequirements": [
{
"minServerVersion": "8.0"
}
],
"createEntities": [
{
"client": {
"id": "client0",
"observeEvents": [
"commandStartedEvent",
"commandSucceededEvent"
]
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "crud-tests"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "coll0"
}
}
],
"initialData": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
],
"_yamlAnchors": {
"namespace": "crud-tests.coll0"
},
"tests": [
{
"description": "client bulkWrite updateOne with sort option",
"operations": [
{
"object": "client0",
"name": "clientBulkWrite",
"arguments": {
"models": [
{
"updateOne": {
"namespace": "crud-tests.coll0",
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"update": {
"$inc": {
"x": 1
}
}
}
}
]
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"commandName": "bulkWrite",
"databaseName": "admin",
"command": {
"bulkWrite": 1,
"ops": [
{
"update": 0,
"filter": {
"_id": {
"$gt": 1
}
},
"updateMods": {
"$inc": {
"x": 1
}
},
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
],
"nsInfo": [
{
"ns": "crud-tests.coll0"
}
]
}
}
},
{
"commandSucceededEvent": {
"reply": {
"ok": 1,
"nErrors": 0,
"nMatched": 1,
"nModified": 1
},
"commandName": "bulkWrite"
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 34
}
]
}
]
}
]
}

View File

@ -52,13 +52,6 @@
}
}
],
"initialData": [
{
"collectionName": "coll0",
"databaseName": "db0",
"documents": []
}
],
"tests": [
{
"description": "Database-level aggregate with $out includes read preference for 5.0+ server",
@ -141,17 +134,6 @@
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "db0",
"documents": [
{
"_id": 1
}
]
}
]
},
{
@ -235,17 +217,6 @@
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "db0",
"documents": [
{
"_id": 1
}
]
}
]
},
{
@ -332,17 +303,6 @@
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "db0",
"documents": [
{
"_id": 1
}
]
}
]
},
{
@ -429,17 +389,6 @@
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "db0",
"documents": [
{
"_id": 1
}
]
}
]
}
]

View File

@ -0,0 +1,232 @@
{
"description": "replaceOne-sort",
"schemaVersion": "1.0",
"createEntities": [
{
"client": {
"id": "client0",
"observeEvents": [
"commandStartedEvent",
"commandSucceededEvent"
]
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "crud-tests"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "coll0"
}
}
],
"initialData": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
],
"tests": [
{
"description": "ReplaceOne with sort option",
"runOnRequirements": [
{
"minServerVersion": "8.0"
}
],
"operations": [
{
"name": "replaceOne",
"object": "collection0",
"arguments": {
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"replacement": {
"x": 1
}
},
"expectResult": {
"matchedCount": 1,
"modifiedCount": 1,
"upsertedCount": 0
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"update": "coll0",
"updates": [
{
"q": {
"_id": {
"$gt": 1
}
},
"u": {
"x": 1
},
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
]
}
}
},
{
"commandSucceededEvent": {
"reply": {
"ok": 1,
"n": 1
},
"commandName": "update"
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 1
}
]
}
]
},
{
"description": "replaceOne with sort option unsupported (server-side error)",
"runOnRequirements": [
{
"maxServerVersion": "7.99"
}
],
"operations": [
{
"name": "replaceOne",
"object": "collection0",
"arguments": {
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"replacement": {
"x": 1
}
},
"expectError": {
"isClientError": false
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"update": "coll0",
"updates": [
{
"q": {
"_id": {
"$gt": 1
}
},
"u": {
"x": 1
},
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
]
}
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
]
}
]
}

View File

@ -0,0 +1,240 @@
{
"description": "updateOne-sort",
"schemaVersion": "1.0",
"createEntities": [
{
"client": {
"id": "client0",
"observeEvents": [
"commandStartedEvent",
"commandSucceededEvent"
]
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "crud-tests"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "coll0"
}
}
],
"initialData": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
],
"tests": [
{
"description": "UpdateOne with sort option",
"runOnRequirements": [
{
"minServerVersion": "8.0"
}
],
"operations": [
{
"name": "updateOne",
"object": "collection0",
"arguments": {
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"update": {
"$inc": {
"x": 1
}
}
},
"expectResult": {
"matchedCount": 1,
"modifiedCount": 1,
"upsertedCount": 0
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"update": "coll0",
"updates": [
{
"q": {
"_id": {
"$gt": 1
}
},
"u": {
"$inc": {
"x": 1
}
},
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
]
}
}
},
{
"commandSucceededEvent": {
"reply": {
"ok": 1,
"n": 1
},
"commandName": "update"
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 34
}
]
}
]
},
{
"description": "updateOne with sort option unsupported (server-side error)",
"runOnRequirements": [
{
"maxServerVersion": "7.99"
}
],
"operations": [
{
"name": "updateOne",
"object": "collection0",
"arguments": {
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"update": {
"$inc": {
"x": 1
}
}
},
"expectError": {
"isClientError": false
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"update": "coll0",
"updates": [
{
"q": {
"_id": {
"$gt": 1
}
},
"u": {
"$inc": {
"x": 1
}
},
"sort": {
"_id": -1
},
"multi": {
"$$unsetOrMatches": false
},
"upsert": {
"$$unsetOrMatches": false
}
}
]
}
}
}
]
}
],
"outcome": [
{
"collectionName": "coll0",
"databaseName": "crud-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
]
}
]
}

View File

@ -969,6 +969,9 @@ class TestBulkWriteConcern(BulkTestBase):
@client_context.require_replica_set
@client_context.require_secondaries_count(1)
def test_write_concern_failure_ordered(self):
self.skipTest("Skipping until PYTHON-4865 is resolved.")
details = None
# Ensure we don't raise on wnote.
coll_ww = self.coll.with_options(write_concern=WriteConcern(w=self.w))
result = coll_ww.bulk_write([DeleteOne({"something": "that does no exist"})])
@ -1049,6 +1052,9 @@ class TestBulkWriteConcern(BulkTestBase):
@client_context.require_replica_set
@client_context.require_secondaries_count(1)
def test_write_concern_failure_unordered(self):
self.skipTest("Skipping until PYTHON-4865 is resolved.")
details = None
# Ensure we don't raise on wnote.
coll_ww = self.coll.with_options(write_concern=WriteConcern(w=self.w))
result = coll_ww.bulk_write([DeleteOne({"something": "that does no exist"})], ordered=False)

View File

@ -958,10 +958,6 @@ def parse_spec_options(opts):
def prepare_spec_arguments(spec, arguments, opname, entity_map, with_txn_callback):
for arg_name in list(arguments):
c2s = camel_to_snake(arg_name)
# PyMongo accepts sort as list of tuples.
if arg_name == "sort":
sort_dict = arguments[arg_name]
arguments[arg_name] = list(sort_dict.items())
# Named "key" instead not fieldName.
if arg_name == "fieldName":
arguments["key"] = arguments.pop(arg_name)