sensu-plugins-mongodb-mrtrotl 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE +22 -0
  4. data/README.md +27 -0
  5. data/bin/check-mongodb-metric.rb +144 -0
  6. data/bin/check-mongodb-query-count.rb +267 -0
  7. data/bin/check-mongodb.py +1644 -0
  8. data/bin/check-mongodb.rb +5 -0
  9. data/bin/metrics-mongodb-replication.rb +254 -0
  10. data/bin/metrics-mongodb.rb +133 -0
  11. data/lib/bson/__init__.py +1347 -0
  12. data/lib/bson/__pycache__/__init__.cpython-310.pyc +0 -0
  13. data/lib/bson/__pycache__/_helpers.cpython-310.pyc +0 -0
  14. data/lib/bson/__pycache__/binary.cpython-310.pyc +0 -0
  15. data/lib/bson/__pycache__/code.cpython-310.pyc +0 -0
  16. data/lib/bson/__pycache__/codec_options.cpython-310.pyc +0 -0
  17. data/lib/bson/__pycache__/dbref.cpython-310.pyc +0 -0
  18. data/lib/bson/__pycache__/decimal128.cpython-310.pyc +0 -0
  19. data/lib/bson/__pycache__/errors.cpython-310.pyc +0 -0
  20. data/lib/bson/__pycache__/int64.cpython-310.pyc +0 -0
  21. data/lib/bson/__pycache__/json_util.cpython-310.pyc +0 -0
  22. data/lib/bson/__pycache__/max_key.cpython-310.pyc +0 -0
  23. data/lib/bson/__pycache__/min_key.cpython-310.pyc +0 -0
  24. data/lib/bson/__pycache__/objectid.cpython-310.pyc +0 -0
  25. data/lib/bson/__pycache__/raw_bson.cpython-310.pyc +0 -0
  26. data/lib/bson/__pycache__/regex.cpython-310.pyc +0 -0
  27. data/lib/bson/__pycache__/son.cpython-310.pyc +0 -0
  28. data/lib/bson/__pycache__/timestamp.cpython-310.pyc +0 -0
  29. data/lib/bson/__pycache__/tz_util.cpython-310.pyc +0 -0
  30. data/lib/bson/_cbson.cpython-310-x86_64-linux-gnu.so +0 -0
  31. data/lib/bson/_helpers.py +41 -0
  32. data/lib/bson/binary.py +364 -0
  33. data/lib/bson/code.py +101 -0
  34. data/lib/bson/codec_options.py +414 -0
  35. data/lib/bson/codec_options.pyi +100 -0
  36. data/lib/bson/dbref.py +133 -0
  37. data/lib/bson/decimal128.py +314 -0
  38. data/lib/bson/errors.py +35 -0
  39. data/lib/bson/int64.py +39 -0
  40. data/lib/bson/json_util.py +874 -0
  41. data/lib/bson/max_key.py +55 -0
  42. data/lib/bson/min_key.py +55 -0
  43. data/lib/bson/objectid.py +286 -0
  44. data/lib/bson/py.typed +2 -0
  45. data/lib/bson/raw_bson.py +175 -0
  46. data/lib/bson/regex.py +135 -0
  47. data/lib/bson/son.py +208 -0
  48. data/lib/bson/timestamp.py +124 -0
  49. data/lib/bson/tz_util.py +52 -0
  50. data/lib/gridfs/__init__.py +1015 -0
  51. data/lib/gridfs/__pycache__/__init__.cpython-310.pyc +0 -0
  52. data/lib/gridfs/__pycache__/errors.cpython-310.pyc +0 -0
  53. data/lib/gridfs/__pycache__/grid_file.cpython-310.pyc +0 -0
  54. data/lib/gridfs/errors.py +33 -0
  55. data/lib/gridfs/grid_file.py +907 -0
  56. data/lib/gridfs/py.typed +2 -0
  57. data/lib/pymongo/__init__.py +185 -0
  58. data/lib/pymongo/__pycache__/__init__.cpython-310.pyc +0 -0
  59. data/lib/pymongo/__pycache__/_csot.cpython-310.pyc +0 -0
  60. data/lib/pymongo/__pycache__/aggregation.cpython-310.pyc +0 -0
  61. data/lib/pymongo/__pycache__/auth.cpython-310.pyc +0 -0
  62. data/lib/pymongo/__pycache__/auth_aws.cpython-310.pyc +0 -0
  63. data/lib/pymongo/__pycache__/bulk.cpython-310.pyc +0 -0
  64. data/lib/pymongo/__pycache__/change_stream.cpython-310.pyc +0 -0
  65. data/lib/pymongo/__pycache__/client_options.cpython-310.pyc +0 -0
  66. data/lib/pymongo/__pycache__/client_session.cpython-310.pyc +0 -0
  67. data/lib/pymongo/__pycache__/collation.cpython-310.pyc +0 -0
  68. data/lib/pymongo/__pycache__/collection.cpython-310.pyc +0 -0
  69. data/lib/pymongo/__pycache__/command_cursor.cpython-310.pyc +0 -0
  70. data/lib/pymongo/__pycache__/common.cpython-310.pyc +0 -0
  71. data/lib/pymongo/__pycache__/compression_support.cpython-310.pyc +0 -0
  72. data/lib/pymongo/__pycache__/cursor.cpython-310.pyc +0 -0
  73. data/lib/pymongo/__pycache__/daemon.cpython-310.pyc +0 -0
  74. data/lib/pymongo/__pycache__/database.cpython-310.pyc +0 -0
  75. data/lib/pymongo/__pycache__/driver_info.cpython-310.pyc +0 -0
  76. data/lib/pymongo/__pycache__/encryption.cpython-310.pyc +0 -0
  77. data/lib/pymongo/__pycache__/encryption_options.cpython-310.pyc +0 -0
  78. data/lib/pymongo/__pycache__/errors.cpython-310.pyc +0 -0
  79. data/lib/pymongo/__pycache__/event_loggers.cpython-310.pyc +0 -0
  80. data/lib/pymongo/__pycache__/hello.cpython-310.pyc +0 -0
  81. data/lib/pymongo/__pycache__/helpers.cpython-310.pyc +0 -0
  82. data/lib/pymongo/__pycache__/max_staleness_selectors.cpython-310.pyc +0 -0
  83. data/lib/pymongo/__pycache__/message.cpython-310.pyc +0 -0
  84. data/lib/pymongo/__pycache__/mongo_client.cpython-310.pyc +0 -0
  85. data/lib/pymongo/__pycache__/monitor.cpython-310.pyc +0 -0
  86. data/lib/pymongo/__pycache__/monitoring.cpython-310.pyc +0 -0
  87. data/lib/pymongo/__pycache__/network.cpython-310.pyc +0 -0
  88. data/lib/pymongo/__pycache__/ocsp_cache.cpython-310.pyc +0 -0
  89. data/lib/pymongo/__pycache__/ocsp_support.cpython-310.pyc +0 -0
  90. data/lib/pymongo/__pycache__/operations.cpython-310.pyc +0 -0
  91. data/lib/pymongo/__pycache__/periodic_executor.cpython-310.pyc +0 -0
  92. data/lib/pymongo/__pycache__/pool.cpython-310.pyc +0 -0
  93. data/lib/pymongo/__pycache__/pyopenssl_context.cpython-310.pyc +0 -0
  94. data/lib/pymongo/__pycache__/read_concern.cpython-310.pyc +0 -0
  95. data/lib/pymongo/__pycache__/read_preferences.cpython-310.pyc +0 -0
  96. data/lib/pymongo/__pycache__/response.cpython-310.pyc +0 -0
  97. data/lib/pymongo/__pycache__/results.cpython-310.pyc +0 -0
  98. data/lib/pymongo/__pycache__/saslprep.cpython-310.pyc +0 -0
  99. data/lib/pymongo/__pycache__/server.cpython-310.pyc +0 -0
  100. data/lib/pymongo/__pycache__/server_api.cpython-310.pyc +0 -0
  101. data/lib/pymongo/__pycache__/server_description.cpython-310.pyc +0 -0
  102. data/lib/pymongo/__pycache__/server_selectors.cpython-310.pyc +0 -0
  103. data/lib/pymongo/__pycache__/server_type.cpython-310.pyc +0 -0
  104. data/lib/pymongo/__pycache__/settings.cpython-310.pyc +0 -0
  105. data/lib/pymongo/__pycache__/socket_checker.cpython-310.pyc +0 -0
  106. data/lib/pymongo/__pycache__/srv_resolver.cpython-310.pyc +0 -0
  107. data/lib/pymongo/__pycache__/ssl_context.cpython-310.pyc +0 -0
  108. data/lib/pymongo/__pycache__/ssl_support.cpython-310.pyc +0 -0
  109. data/lib/pymongo/__pycache__/topology.cpython-310.pyc +0 -0
  110. data/lib/pymongo/__pycache__/topology_description.cpython-310.pyc +0 -0
  111. data/lib/pymongo/__pycache__/typings.cpython-310.pyc +0 -0
  112. data/lib/pymongo/__pycache__/uri_parser.cpython-310.pyc +0 -0
  113. data/lib/pymongo/__pycache__/write_concern.cpython-310.pyc +0 -0
  114. data/lib/pymongo/_cmessage.cpython-310-x86_64-linux-gnu.so +0 -0
  115. data/lib/pymongo/_csot.py +118 -0
  116. data/lib/pymongo/aggregation.py +229 -0
  117. data/lib/pymongo/auth.py +549 -0
  118. data/lib/pymongo/auth_aws.py +94 -0
  119. data/lib/pymongo/bulk.py +513 -0
  120. data/lib/pymongo/change_stream.py +457 -0
  121. data/lib/pymongo/client_options.py +302 -0
  122. data/lib/pymongo/client_session.py +1112 -0
  123. data/lib/pymongo/collation.py +224 -0
  124. data/lib/pymongo/collection.py +3204 -0
  125. data/lib/pymongo/command_cursor.py +353 -0
  126. data/lib/pymongo/common.py +984 -0
  127. data/lib/pymongo/compression_support.py +149 -0
  128. data/lib/pymongo/cursor.py +1345 -0
  129. data/lib/pymongo/daemon.py +141 -0
  130. data/lib/pymongo/database.py +1202 -0
  131. data/lib/pymongo/driver_info.py +42 -0
  132. data/lib/pymongo/encryption.py +884 -0
  133. data/lib/pymongo/encryption_options.py +221 -0
  134. data/lib/pymongo/errors.py +365 -0
  135. data/lib/pymongo/event_loggers.py +221 -0
  136. data/lib/pymongo/hello.py +219 -0
  137. data/lib/pymongo/helpers.py +259 -0
  138. data/lib/pymongo/max_staleness_selectors.py +114 -0
  139. data/lib/pymongo/message.py +1440 -0
  140. data/lib/pymongo/mongo_client.py +2144 -0
  141. data/lib/pymongo/monitor.py +440 -0
  142. data/lib/pymongo/monitoring.py +1801 -0
  143. data/lib/pymongo/network.py +311 -0
  144. data/lib/pymongo/ocsp_cache.py +87 -0
  145. data/lib/pymongo/ocsp_support.py +372 -0
  146. data/lib/pymongo/operations.py +507 -0
  147. data/lib/pymongo/periodic_executor.py +183 -0
  148. data/lib/pymongo/pool.py +1660 -0
  149. data/lib/pymongo/py.typed +2 -0
  150. data/lib/pymongo/pyopenssl_context.py +383 -0
  151. data/lib/pymongo/read_concern.py +75 -0
  152. data/lib/pymongo/read_preferences.py +609 -0
  153. data/lib/pymongo/response.py +109 -0
  154. data/lib/pymongo/results.py +217 -0
  155. data/lib/pymongo/saslprep.py +113 -0
  156. data/lib/pymongo/server.py +247 -0
  157. data/lib/pymongo/server_api.py +170 -0
  158. data/lib/pymongo/server_description.py +285 -0
  159. data/lib/pymongo/server_selectors.py +153 -0
  160. data/lib/pymongo/server_type.py +32 -0
  161. data/lib/pymongo/settings.py +159 -0
  162. data/lib/pymongo/socket_checker.py +104 -0
  163. data/lib/pymongo/srv_resolver.py +126 -0
  164. data/lib/pymongo/ssl_context.py +39 -0
  165. data/lib/pymongo/ssl_support.py +99 -0
  166. data/lib/pymongo/topology.py +890 -0
  167. data/lib/pymongo/topology_description.py +639 -0
  168. data/lib/pymongo/typings.py +39 -0
  169. data/lib/pymongo/uri_parser.py +624 -0
  170. data/lib/pymongo/write_concern.py +129 -0
  171. data/lib/pymongo-4.2.0.dist-info/INSTALLER +1 -0
  172. data/lib/pymongo-4.2.0.dist-info/LICENSE +201 -0
  173. data/lib/pymongo-4.2.0.dist-info/METADATA +250 -0
  174. data/lib/pymongo-4.2.0.dist-info/RECORD +167 -0
  175. data/lib/pymongo-4.2.0.dist-info/REQUESTED +0 -0
  176. data/lib/pymongo-4.2.0.dist-info/WHEEL +6 -0
  177. data/lib/pymongo-4.2.0.dist-info/top_level.txt +3 -0
  178. data/lib/sensu-plugins-mongodb/metrics.rb +391 -0
  179. data/lib/sensu-plugins-mongodb/version.rb +9 -0
  180. data/lib/sensu-plugins-mongodb.rb +1 -0
  181. metadata +407 -0
@@ -0,0 +1,3204 @@
1
+ # Copyright 2009-present MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Collection level utilities for Mongo."""
16
+
17
+ from collections import abc
18
+ from typing import (
19
+ TYPE_CHECKING,
20
+ Any,
21
+ Generic,
22
+ Iterable,
23
+ List,
24
+ Mapping,
25
+ MutableMapping,
26
+ NoReturn,
27
+ Optional,
28
+ Sequence,
29
+ Tuple,
30
+ Union,
31
+ )
32
+
33
+ from bson.codec_options import CodecOptions
34
+ from bson.objectid import ObjectId
35
+ from bson.raw_bson import RawBSONDocument
36
+ from bson.son import SON
37
+ from bson.timestamp import Timestamp
38
+ from pymongo import ASCENDING, _csot, common, helpers, message
39
+ from pymongo.aggregation import (
40
+ _CollectionAggregationCommand,
41
+ _CollectionRawAggregationCommand,
42
+ )
43
+ from pymongo.bulk import _Bulk
44
+ from pymongo.change_stream import CollectionChangeStream
45
+ from pymongo.collation import validate_collation_or_none
46
+ from pymongo.command_cursor import CommandCursor, RawBatchCommandCursor
47
+ from pymongo.common import _ecc_coll_name, _ecoc_coll_name, _esc_coll_name
48
+ from pymongo.cursor import Cursor, RawBatchCursor
49
+ from pymongo.errors import (
50
+ ConfigurationError,
51
+ InvalidName,
52
+ InvalidOperation,
53
+ OperationFailure,
54
+ )
55
+ from pymongo.helpers import _check_write_command_response
56
+ from pymongo.message import _UNICODE_REPLACE_CODEC_OPTIONS
57
+ from pymongo.operations import (
58
+ DeleteMany,
59
+ DeleteOne,
60
+ IndexModel,
61
+ InsertOne,
62
+ ReplaceOne,
63
+ UpdateMany,
64
+ UpdateOne,
65
+ )
66
+ from pymongo.read_preferences import ReadPreference, _ServerMode
67
+ from pymongo.results import (
68
+ BulkWriteResult,
69
+ DeleteResult,
70
+ InsertManyResult,
71
+ InsertOneResult,
72
+ UpdateResult,
73
+ )
74
+ from pymongo.typings import _CollationIn, _DocumentIn, _DocumentType, _Pipeline
75
+ from pymongo.write_concern import WriteConcern
76
+
77
+ _FIND_AND_MODIFY_DOC_FIELDS = {"value": 1}
78
+
79
+
80
+ _WriteOp = Union[InsertOne, DeleteOne, DeleteMany, ReplaceOne, UpdateOne, UpdateMany]
81
+ # Hint supports index name, "myIndex", or list of index pairs: [('x', 1), ('y', -1)]
82
+ _IndexList = Sequence[Tuple[str, Union[int, str, Mapping[str, Any]]]]
83
+ _IndexKeyHint = Union[str, _IndexList]
84
+
85
+
86
+ class ReturnDocument(object):
87
+ """An enum used with
88
+ :meth:`~pymongo.collection.Collection.find_one_and_replace` and
89
+ :meth:`~pymongo.collection.Collection.find_one_and_update`.
90
+ """
91
+
92
+ BEFORE = False
93
+ """Return the original document before it was updated/replaced, or
94
+ ``None`` if no document matches the query.
95
+ """
96
+ AFTER = True
97
+ """Return the updated/replaced or inserted document."""
98
+
99
+
100
+ if TYPE_CHECKING:
101
+ from pymongo.client_session import ClientSession
102
+ from pymongo.database import Database
103
+ from pymongo.read_concern import ReadConcern
104
+
105
+
106
+ class Collection(common.BaseObject, Generic[_DocumentType]):
107
+ """A Mongo collection."""
108
+
109
+ def __init__(
110
+ self,
111
+ database: "Database[_DocumentType]",
112
+ name: str,
113
+ create: Optional[bool] = False,
114
+ codec_options: Optional[CodecOptions] = None,
115
+ read_preference: Optional[_ServerMode] = None,
116
+ write_concern: Optional[WriteConcern] = None,
117
+ read_concern: Optional["ReadConcern"] = None,
118
+ session: Optional["ClientSession"] = None,
119
+ **kwargs: Any,
120
+ ) -> None:
121
+ """Get / create a Mongo collection.
122
+
123
+ Raises :class:`TypeError` if `name` is not an instance of
124
+ :class:`basestring` (:class:`str` in python 3). Raises
125
+ :class:`~pymongo.errors.InvalidName` if `name` is not a valid
126
+ collection name. Any additional keyword arguments will be used
127
+ as options passed to the create command. See
128
+ :meth:`~pymongo.database.Database.create_collection` for valid
129
+ options.
130
+
131
+ If `create` is ``True``, `collation` is specified, or any additional
132
+ keyword arguments are present, a ``create`` command will be
133
+ sent, using ``session`` if specified. Otherwise, a ``create`` command
134
+ will not be sent and the collection will be created implicitly on first
135
+ use. The optional ``session`` argument is *only* used for the ``create``
136
+ command, it is not associated with the collection afterward.
137
+
138
+ :Parameters:
139
+ - `database`: the database to get a collection from
140
+ - `name`: the name of the collection to get
141
+ - `create` (optional): if ``True``, force collection
142
+ creation even without options being set
143
+ - `codec_options` (optional): An instance of
144
+ :class:`~bson.codec_options.CodecOptions`. If ``None`` (the
145
+ default) database.codec_options is used.
146
+ - `read_preference` (optional): The read preference to use. If
147
+ ``None`` (the default) database.read_preference is used.
148
+ - `write_concern` (optional): An instance of
149
+ :class:`~pymongo.write_concern.WriteConcern`. If ``None`` (the
150
+ default) database.write_concern is used.
151
+ - `read_concern` (optional): An instance of
152
+ :class:`~pymongo.read_concern.ReadConcern`. If ``None`` (the
153
+ default) database.read_concern is used.
154
+ - `collation` (optional): An instance of
155
+ :class:`~pymongo.collation.Collation`. If a collation is provided,
156
+ it will be passed to the create collection command.
157
+ - `session` (optional): a
158
+ :class:`~pymongo.client_session.ClientSession` that is used with
159
+ the create collection command
160
+ - `**kwargs` (optional): additional keyword arguments will
161
+ be passed as options for the create collection command
162
+
163
+ .. versionchanged:: 4.2
164
+ Added the ``clusteredIndex`` and ``encryptedFields`` parameters.
165
+
166
+ .. versionchanged:: 4.0
167
+ Removed the reindex, map_reduce, inline_map_reduce,
168
+ parallel_scan, initialize_unordered_bulk_op,
169
+ initialize_ordered_bulk_op, group, count, insert, save,
170
+ update, remove, find_and_modify, and ensure_index methods. See the
171
+ :ref:`pymongo4-migration-guide`.
172
+
173
+ .. versionchanged:: 3.6
174
+ Added ``session`` parameter.
175
+
176
+ .. versionchanged:: 3.4
177
+ Support the `collation` option.
178
+
179
+ .. versionchanged:: 3.2
180
+ Added the read_concern option.
181
+
182
+ .. versionchanged:: 3.0
183
+ Added the codec_options, read_preference, and write_concern options.
184
+ Removed the uuid_subtype attribute.
185
+ :class:`~pymongo.collection.Collection` no longer returns an
186
+ instance of :class:`~pymongo.collection.Collection` for attribute
187
+ names with leading underscores. You must use dict-style lookups
188
+ instead::
189
+
190
+ collection['__my_collection__']
191
+
192
+ Not:
193
+
194
+ collection.__my_collection__
195
+
196
+ .. seealso:: The MongoDB documentation on `collections <https://dochub.mongodb.org/core/collections>`_.
197
+ """
198
+ super(Collection, self).__init__(
199
+ codec_options or database.codec_options,
200
+ read_preference or database.read_preference,
201
+ write_concern or database.write_concern,
202
+ read_concern or database.read_concern,
203
+ )
204
+ if not isinstance(name, str):
205
+ raise TypeError("name must be an instance of str")
206
+
207
+ if not name or ".." in name:
208
+ raise InvalidName("collection names cannot be empty")
209
+ if "$" in name and not (name.startswith("oplog.$main") or name.startswith("$cmd")):
210
+ raise InvalidName("collection names must not contain '$': %r" % name)
211
+ if name[0] == "." or name[-1] == ".":
212
+ raise InvalidName("collection names must not start or end with '.': %r" % name)
213
+ if "\x00" in name:
214
+ raise InvalidName("collection names must not contain the null character")
215
+ collation = validate_collation_or_none(kwargs.pop("collation", None))
216
+
217
+ self.__database: Database[_DocumentType] = database
218
+ self.__name = name
219
+ self.__full_name = "%s.%s" % (self.__database.name, self.__name)
220
+ self.__write_response_codec_options = self.codec_options._replace(
221
+ unicode_decode_error_handler="replace", document_class=dict
222
+ )
223
+ self._timeout = database.client.options.timeout
224
+ encrypted_fields = kwargs.pop("encryptedFields", None)
225
+ if create or kwargs or collation:
226
+ if encrypted_fields:
227
+ common.validate_is_mapping("encrypted_fields", encrypted_fields)
228
+ opts = {"clusteredIndex": {"key": {"_id": 1}, "unique": True}}
229
+ self.__create(_esc_coll_name(encrypted_fields, name), opts, None, session)
230
+ self.__create(_ecc_coll_name(encrypted_fields, name), opts, None, session)
231
+ self.__create(_ecoc_coll_name(encrypted_fields, name), opts, None, session)
232
+ self.__create(name, kwargs, collation, session, encrypted_fields=encrypted_fields)
233
+ self.create_index([("__safeContent__", ASCENDING)], session)
234
+ else:
235
+ self.__create(name, kwargs, collation, session)
236
+
237
+ def _socket_for_reads(self, session):
238
+ return self.__database.client._socket_for_reads(self._read_preference_for(session), session)
239
+
240
+ def _socket_for_writes(self, session):
241
+ return self.__database.client._socket_for_writes(session)
242
+
243
+ def _command(
244
+ self,
245
+ sock_info,
246
+ command,
247
+ read_preference=None,
248
+ codec_options=None,
249
+ check=True,
250
+ allowable_errors=None,
251
+ read_concern=None,
252
+ write_concern=None,
253
+ collation=None,
254
+ session=None,
255
+ retryable_write=False,
256
+ user_fields=None,
257
+ ):
258
+ """Internal command helper.
259
+
260
+ :Parameters:
261
+ - `sock_info` - A SocketInfo instance.
262
+ - `command` - The command itself, as a :class:`~bson.son.SON` instance.
263
+ - `codec_options` (optional) - An instance of
264
+ :class:`~bson.codec_options.CodecOptions`.
265
+ - `check`: raise OperationFailure if there are errors
266
+ - `allowable_errors`: errors to ignore if `check` is True
267
+ - `read_concern` (optional) - An instance of
268
+ :class:`~pymongo.read_concern.ReadConcern`.
269
+ - `write_concern`: An instance of
270
+ :class:`~pymongo.write_concern.WriteConcern`.
271
+ - `collation` (optional) - An instance of
272
+ :class:`~pymongo.collation.Collation`.
273
+ - `session` (optional): a
274
+ :class:`~pymongo.client_session.ClientSession`.
275
+ - `retryable_write` (optional): True if this command is a retryable
276
+ write.
277
+ - `user_fields` (optional): Response fields that should be decoded
278
+ using the TypeDecoders from codec_options, passed to
279
+ bson._decode_all_selective.
280
+
281
+ :Returns:
282
+ The result document.
283
+ """
284
+ with self.__database.client._tmp_session(session) as s:
285
+ return sock_info.command(
286
+ self.__database.name,
287
+ command,
288
+ read_preference or self._read_preference_for(session),
289
+ codec_options or self.codec_options,
290
+ check,
291
+ allowable_errors,
292
+ read_concern=read_concern,
293
+ write_concern=write_concern,
294
+ parse_write_concern_error=True,
295
+ collation=collation,
296
+ session=s,
297
+ client=self.__database.client,
298
+ retryable_write=retryable_write,
299
+ user_fields=user_fields,
300
+ )
301
+
302
+ def __create(self, name, options, collation, session, encrypted_fields=None):
303
+ """Sends a create command with the given options."""
304
+ cmd = SON([("create", name)])
305
+ if encrypted_fields:
306
+ cmd["encryptedFields"] = encrypted_fields
307
+
308
+ if options:
309
+ if "size" in options:
310
+ options["size"] = float(options["size"])
311
+ cmd.update(options)
312
+ with self._socket_for_writes(session) as sock_info:
313
+ self._command(
314
+ sock_info,
315
+ cmd,
316
+ read_preference=ReadPreference.PRIMARY,
317
+ write_concern=self._write_concern_for(session),
318
+ collation=collation,
319
+ session=session,
320
+ )
321
+
322
+ def __getattr__(self, name: str) -> "Collection[_DocumentType]":
323
+ """Get a sub-collection of this collection by name.
324
+
325
+ Raises InvalidName if an invalid collection name is used.
326
+
327
+ :Parameters:
328
+ - `name`: the name of the collection to get
329
+ """
330
+ if name.startswith("_"):
331
+ full_name = "%s.%s" % (self.__name, name)
332
+ raise AttributeError(
333
+ "Collection has no attribute %r. To access the %s"
334
+ " collection, use database['%s']." % (name, full_name, full_name)
335
+ )
336
+ return self.__getitem__(name)
337
+
338
+ def __getitem__(self, name: str) -> "Collection[_DocumentType]":
339
+ return Collection(
340
+ self.__database,
341
+ "%s.%s" % (self.__name, name),
342
+ False,
343
+ self.codec_options,
344
+ self.read_preference,
345
+ self.write_concern,
346
+ self.read_concern,
347
+ )
348
+
349
+ def __repr__(self):
350
+ return "Collection(%r, %r)" % (self.__database, self.__name)
351
+
352
+ def __eq__(self, other: Any) -> bool:
353
+ if isinstance(other, Collection):
354
+ return self.__database == other.database and self.__name == other.name
355
+ return NotImplemented
356
+
357
+ def __ne__(self, other: Any) -> bool:
358
+ return not self == other
359
+
360
+ def __hash__(self) -> int:
361
+ return hash((self.__database, self.__name))
362
+
363
+ def __bool__(self) -> NoReturn:
364
+ raise NotImplementedError(
365
+ "Collection objects do not implement truth "
366
+ "value testing or bool(). Please compare "
367
+ "with None instead: collection is not None"
368
+ )
369
+
370
+ @property
371
+ def full_name(self) -> str:
372
+ """The full name of this :class:`Collection`.
373
+
374
+ The full name is of the form `database_name.collection_name`.
375
+ """
376
+ return self.__full_name
377
+
378
+ @property
379
+ def name(self) -> str:
380
+ """The name of this :class:`Collection`."""
381
+ return self.__name
382
+
383
+ @property
384
+ def database(self) -> "Database[_DocumentType]":
385
+ """The :class:`~pymongo.database.Database` that this
386
+ :class:`Collection` is a part of.
387
+ """
388
+ return self.__database
389
+
390
+ def with_options(
391
+ self,
392
+ codec_options: Optional[CodecOptions] = None,
393
+ read_preference: Optional[_ServerMode] = None,
394
+ write_concern: Optional[WriteConcern] = None,
395
+ read_concern: Optional["ReadConcern"] = None,
396
+ ) -> "Collection[_DocumentType]":
397
+ """Get a clone of this collection changing the specified settings.
398
+
399
+ >>> coll1.read_preference
400
+ Primary()
401
+ >>> from pymongo import ReadPreference
402
+ >>> coll2 = coll1.with_options(read_preference=ReadPreference.SECONDARY)
403
+ >>> coll1.read_preference
404
+ Primary()
405
+ >>> coll2.read_preference
406
+ Secondary(tag_sets=None)
407
+
408
+ :Parameters:
409
+ - `codec_options` (optional): An instance of
410
+ :class:`~bson.codec_options.CodecOptions`. If ``None`` (the
411
+ default) the :attr:`codec_options` of this :class:`Collection`
412
+ is used.
413
+ - `read_preference` (optional): The read preference to use. If
414
+ ``None`` (the default) the :attr:`read_preference` of this
415
+ :class:`Collection` is used. See :mod:`~pymongo.read_preferences`
416
+ for options.
417
+ - `write_concern` (optional): An instance of
418
+ :class:`~pymongo.write_concern.WriteConcern`. If ``None`` (the
419
+ default) the :attr:`write_concern` of this :class:`Collection`
420
+ is used.
421
+ - `read_concern` (optional): An instance of
422
+ :class:`~pymongo.read_concern.ReadConcern`. If ``None`` (the
423
+ default) the :attr:`read_concern` of this :class:`Collection`
424
+ is used.
425
+ """
426
+ return Collection(
427
+ self.__database,
428
+ self.__name,
429
+ False,
430
+ codec_options or self.codec_options,
431
+ read_preference or self.read_preference,
432
+ write_concern or self.write_concern,
433
+ read_concern or self.read_concern,
434
+ )
435
+
436
+ @_csot.apply
437
+ def bulk_write(
438
+ self,
439
+ requests: Sequence[_WriteOp],
440
+ ordered: bool = True,
441
+ bypass_document_validation: bool = False,
442
+ session: Optional["ClientSession"] = None,
443
+ comment: Optional[Any] = None,
444
+ let: Optional[Mapping] = None,
445
+ ) -> BulkWriteResult:
446
+ """Send a batch of write operations to the server.
447
+
448
+ Requests are passed as a list of write operation instances (
449
+ :class:`~pymongo.operations.InsertOne`,
450
+ :class:`~pymongo.operations.UpdateOne`,
451
+ :class:`~pymongo.operations.UpdateMany`,
452
+ :class:`~pymongo.operations.ReplaceOne`,
453
+ :class:`~pymongo.operations.DeleteOne`, or
454
+ :class:`~pymongo.operations.DeleteMany`).
455
+
456
+ >>> for doc in db.test.find({}):
457
+ ... print(doc)
458
+ ...
459
+ {'x': 1, '_id': ObjectId('54f62e60fba5226811f634ef')}
460
+ {'x': 1, '_id': ObjectId('54f62e60fba5226811f634f0')}
461
+ >>> # DeleteMany, UpdateOne, and UpdateMany are also available.
462
+ ...
463
+ >>> from pymongo import InsertOne, DeleteOne, ReplaceOne
464
+ >>> requests = [InsertOne({'y': 1}), DeleteOne({'x': 1}),
465
+ ... ReplaceOne({'w': 1}, {'z': 1}, upsert=True)]
466
+ >>> result = db.test.bulk_write(requests)
467
+ >>> result.inserted_count
468
+ 1
469
+ >>> result.deleted_count
470
+ 1
471
+ >>> result.modified_count
472
+ 0
473
+ >>> result.upserted_ids
474
+ {2: ObjectId('54f62ee28891e756a6e1abd5')}
475
+ >>> for doc in db.test.find({}):
476
+ ... print(doc)
477
+ ...
478
+ {'x': 1, '_id': ObjectId('54f62e60fba5226811f634f0')}
479
+ {'y': 1, '_id': ObjectId('54f62ee2fba5226811f634f1')}
480
+ {'z': 1, '_id': ObjectId('54f62ee28891e756a6e1abd5')}
481
+
482
+ :Parameters:
483
+ - `requests`: A list of write operations (see examples above).
484
+ - `ordered` (optional): If ``True`` (the default) requests will be
485
+ performed on the server serially, in the order provided. If an error
486
+ occurs all remaining operations are aborted. If ``False`` requests
487
+ will be performed on the server in arbitrary order, possibly in
488
+ parallel, and all operations will be attempted.
489
+ - `bypass_document_validation`: (optional) If ``True``, allows the
490
+ write to opt-out of document level validation. Default is
491
+ ``False``.
492
+ - `session` (optional): a
493
+ :class:`~pymongo.client_session.ClientSession`.
494
+ - `comment` (optional): A user-provided comment to attach to this
495
+ command.
496
+ - `let` (optional): Map of parameter names and values. Values must be
497
+ constant or closed expressions that do not reference document
498
+ fields. Parameters can then be accessed as variables in an
499
+ aggregate expression context (e.g. "$$var").
500
+
501
+ :Returns:
502
+ An instance of :class:`~pymongo.results.BulkWriteResult`.
503
+
504
+ .. seealso:: :ref:`writes-and-ids`
505
+
506
+ .. note:: `bypass_document_validation` requires server version
507
+ **>= 3.2**
508
+
509
+ .. versionchanged:: 4.1
510
+ Added ``comment`` parameter.
511
+ Added ``let`` parameter.
512
+
513
+ .. versionchanged:: 3.6
514
+ Added ``session`` parameter.
515
+
516
+ .. versionchanged:: 3.2
517
+ Added bypass_document_validation support
518
+
519
+ .. versionadded:: 3.0
520
+ """
521
+ common.validate_list("requests", requests)
522
+
523
+ blk = _Bulk(self, ordered, bypass_document_validation, comment=comment, let=let)
524
+ for request in requests:
525
+ try:
526
+ request._add_to_bulk(blk)
527
+ except AttributeError:
528
+ raise TypeError("%r is not a valid request" % (request,))
529
+
530
+ write_concern = self._write_concern_for(session)
531
+ bulk_api_result = blk.execute(write_concern, session)
532
+ if bulk_api_result is not None:
533
+ return BulkWriteResult(bulk_api_result, True)
534
+ return BulkWriteResult({}, False)
535
+
536
+ def _insert_one(
537
+ self, doc, ordered, write_concern, op_id, bypass_doc_val, session, comment=None
538
+ ):
539
+ """Internal helper for inserting a single document."""
540
+ write_concern = write_concern or self.write_concern
541
+ acknowledged = write_concern.acknowledged
542
+ command = SON([("insert", self.name), ("ordered", ordered), ("documents", [doc])])
543
+ if comment is not None:
544
+ command["comment"] = comment
545
+
546
+ def _insert_command(session, sock_info, retryable_write):
547
+ if bypass_doc_val:
548
+ command["bypassDocumentValidation"] = True
549
+
550
+ result = sock_info.command(
551
+ self.__database.name,
552
+ command,
553
+ write_concern=write_concern,
554
+ codec_options=self.__write_response_codec_options,
555
+ session=session,
556
+ client=self.__database.client,
557
+ retryable_write=retryable_write,
558
+ )
559
+
560
+ _check_write_command_response(result)
561
+
562
+ self.__database.client._retryable_write(acknowledged, _insert_command, session)
563
+
564
+ if not isinstance(doc, RawBSONDocument):
565
+ return doc.get("_id")
566
+
567
+ def insert_one(
568
+ self,
569
+ document: _DocumentIn,
570
+ bypass_document_validation: bool = False,
571
+ session: Optional["ClientSession"] = None,
572
+ comment: Optional[Any] = None,
573
+ ) -> InsertOneResult:
574
+ """Insert a single document.
575
+
576
+ >>> db.test.count_documents({'x': 1})
577
+ 0
578
+ >>> result = db.test.insert_one({'x': 1})
579
+ >>> result.inserted_id
580
+ ObjectId('54f112defba522406c9cc208')
581
+ >>> db.test.find_one({'x': 1})
582
+ {'x': 1, '_id': ObjectId('54f112defba522406c9cc208')}
583
+
584
+ :Parameters:
585
+ - `document`: The document to insert. Must be a mutable mapping
586
+ type. If the document does not have an _id field one will be
587
+ added automatically.
588
+ - `bypass_document_validation`: (optional) If ``True``, allows the
589
+ write to opt-out of document level validation. Default is
590
+ ``False``.
591
+ - `session` (optional): a
592
+ :class:`~pymongo.client_session.ClientSession`.
593
+ - `comment` (optional): A user-provided comment to attach to this
594
+ command.
595
+
596
+ :Returns:
597
+ - An instance of :class:`~pymongo.results.InsertOneResult`.
598
+
599
+ .. seealso:: :ref:`writes-and-ids`
600
+
601
+ .. note:: `bypass_document_validation` requires server version
602
+ **>= 3.2**
603
+
604
+ .. versionchanged:: 4.1
605
+ Added ``comment`` parameter.
606
+
607
+ .. versionchanged:: 3.6
608
+ Added ``session`` parameter.
609
+
610
+ .. versionchanged:: 3.2
611
+ Added bypass_document_validation support
612
+
613
+ .. versionadded:: 3.0
614
+ """
615
+ common.validate_is_document_type("document", document)
616
+ if not (isinstance(document, RawBSONDocument) or "_id" in document):
617
+ document["_id"] = ObjectId()
618
+
619
+ write_concern = self._write_concern_for(session)
620
+ return InsertOneResult(
621
+ self._insert_one(
622
+ document,
623
+ ordered=True,
624
+ write_concern=write_concern,
625
+ op_id=None,
626
+ bypass_doc_val=bypass_document_validation,
627
+ session=session,
628
+ comment=comment,
629
+ ),
630
+ write_concern.acknowledged,
631
+ )
632
+
633
+ @_csot.apply
634
+ def insert_many(
635
+ self,
636
+ documents: Iterable[_DocumentIn],
637
+ ordered: bool = True,
638
+ bypass_document_validation: bool = False,
639
+ session: Optional["ClientSession"] = None,
640
+ comment: Optional[Any] = None,
641
+ ) -> InsertManyResult:
642
+ """Insert an iterable of documents.
643
+
644
+ >>> db.test.count_documents({})
645
+ 0
646
+ >>> result = db.test.insert_many([{'x': i} for i in range(2)])
647
+ >>> result.inserted_ids
648
+ [ObjectId('54f113fffba522406c9cc20e'), ObjectId('54f113fffba522406c9cc20f')]
649
+ >>> db.test.count_documents({})
650
+ 2
651
+
652
+ :Parameters:
653
+ - `documents`: A iterable of documents to insert.
654
+ - `ordered` (optional): If ``True`` (the default) documents will be
655
+ inserted on the server serially, in the order provided. If an error
656
+ occurs all remaining inserts are aborted. If ``False``, documents
657
+ will be inserted on the server in arbitrary order, possibly in
658
+ parallel, and all document inserts will be attempted.
659
+ - `bypass_document_validation`: (optional) If ``True``, allows the
660
+ write to opt-out of document level validation. Default is
661
+ ``False``.
662
+ - `session` (optional): a
663
+ :class:`~pymongo.client_session.ClientSession`.
664
+ - `comment` (optional): A user-provided comment to attach to this
665
+ command.
666
+
667
+ :Returns:
668
+ An instance of :class:`~pymongo.results.InsertManyResult`.
669
+
670
+ .. seealso:: :ref:`writes-and-ids`
671
+
672
+ .. note:: `bypass_document_validation` requires server version
673
+ **>= 3.2**
674
+
675
+ .. versionchanged:: 4.1
676
+ Added ``comment`` parameter.
677
+
678
+ .. versionchanged:: 3.6
679
+ Added ``session`` parameter.
680
+
681
+ .. versionchanged:: 3.2
682
+ Added bypass_document_validation support
683
+
684
+ .. versionadded:: 3.0
685
+ """
686
+ if (
687
+ not isinstance(documents, abc.Iterable)
688
+ or isinstance(documents, abc.Mapping)
689
+ or not documents
690
+ ):
691
+ raise TypeError("documents must be a non-empty list")
692
+ inserted_ids: List[ObjectId] = []
693
+
694
+ def gen():
695
+ """A generator that validates documents and handles _ids."""
696
+ for document in documents:
697
+ common.validate_is_document_type("document", document)
698
+ if not isinstance(document, RawBSONDocument):
699
+ if "_id" not in document:
700
+ document["_id"] = ObjectId()
701
+ inserted_ids.append(document["_id"])
702
+ yield (message._INSERT, document)
703
+
704
+ write_concern = self._write_concern_for(session)
705
+ blk = _Bulk(self, ordered, bypass_document_validation, comment=comment)
706
+ blk.ops = [doc for doc in gen()]
707
+ blk.execute(write_concern, session=session)
708
+ return InsertManyResult(inserted_ids, write_concern.acknowledged)
709
+
710
+ def _update(
711
+ self,
712
+ sock_info,
713
+ criteria,
714
+ document,
715
+ upsert=False,
716
+ multi=False,
717
+ write_concern=None,
718
+ op_id=None,
719
+ ordered=True,
720
+ bypass_doc_val=False,
721
+ collation=None,
722
+ array_filters=None,
723
+ hint=None,
724
+ session=None,
725
+ retryable_write=False,
726
+ let=None,
727
+ comment=None,
728
+ ):
729
+ """Internal update / replace helper."""
730
+ common.validate_boolean("upsert", upsert)
731
+ collation = validate_collation_or_none(collation)
732
+ write_concern = write_concern or self.write_concern
733
+ acknowledged = write_concern.acknowledged
734
+ update_doc = SON([("q", criteria), ("u", document), ("multi", multi), ("upsert", upsert)])
735
+ if collation is not None:
736
+ if not acknowledged:
737
+ raise ConfigurationError("Collation is unsupported for unacknowledged writes.")
738
+ else:
739
+ update_doc["collation"] = collation
740
+ if array_filters is not None:
741
+ if not acknowledged:
742
+ raise ConfigurationError("arrayFilters is unsupported for unacknowledged writes.")
743
+ else:
744
+ update_doc["arrayFilters"] = array_filters
745
+ if hint is not None:
746
+ if not acknowledged and sock_info.max_wire_version < 8:
747
+ raise ConfigurationError(
748
+ "Must be connected to MongoDB 4.2+ to use hint on unacknowledged update commands."
749
+ )
750
+ if not isinstance(hint, str):
751
+ hint = helpers._index_document(hint)
752
+ update_doc["hint"] = hint
753
+ command = SON([("update", self.name), ("ordered", ordered), ("updates", [update_doc])])
754
+ if let is not None:
755
+ common.validate_is_mapping("let", let)
756
+ command["let"] = let
757
+
758
+ if comment is not None:
759
+ command["comment"] = comment
760
+ # Update command.
761
+ if bypass_doc_val:
762
+ command["bypassDocumentValidation"] = True
763
+
764
+ # The command result has to be published for APM unmodified
765
+ # so we make a shallow copy here before adding updatedExisting.
766
+ result = sock_info.command(
767
+ self.__database.name,
768
+ command,
769
+ write_concern=write_concern,
770
+ codec_options=self.__write_response_codec_options,
771
+ session=session,
772
+ client=self.__database.client,
773
+ retryable_write=retryable_write,
774
+ ).copy()
775
+ _check_write_command_response(result)
776
+ # Add the updatedExisting field for compatibility.
777
+ if result.get("n") and "upserted" not in result:
778
+ result["updatedExisting"] = True
779
+ else:
780
+ result["updatedExisting"] = False
781
+ # MongoDB >= 2.6.0 returns the upsert _id in an array
782
+ # element. Break it out for backward compatibility.
783
+ if "upserted" in result:
784
+ result["upserted"] = result["upserted"][0]["_id"]
785
+
786
+ if not acknowledged:
787
+ return None
788
+ return result
789
+
790
+ def _update_retryable(
791
+ self,
792
+ criteria,
793
+ document,
794
+ upsert=False,
795
+ multi=False,
796
+ write_concern=None,
797
+ op_id=None,
798
+ ordered=True,
799
+ bypass_doc_val=False,
800
+ collation=None,
801
+ array_filters=None,
802
+ hint=None,
803
+ session=None,
804
+ let=None,
805
+ comment=None,
806
+ ):
807
+ """Internal update / replace helper."""
808
+
809
+ def _update(session, sock_info, retryable_write):
810
+ return self._update(
811
+ sock_info,
812
+ criteria,
813
+ document,
814
+ upsert=upsert,
815
+ multi=multi,
816
+ write_concern=write_concern,
817
+ op_id=op_id,
818
+ ordered=ordered,
819
+ bypass_doc_val=bypass_doc_val,
820
+ collation=collation,
821
+ array_filters=array_filters,
822
+ hint=hint,
823
+ session=session,
824
+ retryable_write=retryable_write,
825
+ let=let,
826
+ comment=comment,
827
+ )
828
+
829
+ return self.__database.client._retryable_write(
830
+ (write_concern or self.write_concern).acknowledged and not multi, _update, session
831
+ )
832
+
833
+ def replace_one(
834
+ self,
835
+ filter: Mapping[str, Any],
836
+ replacement: Mapping[str, Any],
837
+ upsert: bool = False,
838
+ bypass_document_validation: bool = False,
839
+ collation: Optional[_CollationIn] = None,
840
+ hint: Optional[_IndexKeyHint] = None,
841
+ session: Optional["ClientSession"] = None,
842
+ let: Optional[Mapping[str, Any]] = None,
843
+ comment: Optional[Any] = None,
844
+ ) -> UpdateResult:
845
+ """Replace a single document matching the filter.
846
+
847
+ >>> for doc in db.test.find({}):
848
+ ... print(doc)
849
+ ...
850
+ {'x': 1, '_id': ObjectId('54f4c5befba5220aa4d6dee7')}
851
+ >>> result = db.test.replace_one({'x': 1}, {'y': 1})
852
+ >>> result.matched_count
853
+ 1
854
+ >>> result.modified_count
855
+ 1
856
+ >>> for doc in db.test.find({}):
857
+ ... print(doc)
858
+ ...
859
+ {'y': 1, '_id': ObjectId('54f4c5befba5220aa4d6dee7')}
860
+
861
+ The *upsert* option can be used to insert a new document if a matching
862
+ document does not exist.
863
+
864
+ >>> result = db.test.replace_one({'x': 1}, {'x': 1}, True)
865
+ >>> result.matched_count
866
+ 0
867
+ >>> result.modified_count
868
+ 0
869
+ >>> result.upserted_id
870
+ ObjectId('54f11e5c8891e756a6e1abd4')
871
+ >>> db.test.find_one({'x': 1})
872
+ {'x': 1, '_id': ObjectId('54f11e5c8891e756a6e1abd4')}
873
+
874
+ :Parameters:
875
+ - `filter`: A query that matches the document to replace.
876
+ - `replacement`: The new document.
877
+ - `upsert` (optional): If ``True``, perform an insert if no documents
878
+ match the filter.
879
+ - `bypass_document_validation`: (optional) If ``True``, allows the
880
+ write to opt-out of document level validation. Default is
881
+ ``False``.
882
+ - `collation` (optional): An instance of
883
+ :class:`~pymongo.collation.Collation`.
884
+ - `hint` (optional): An index to use to support the query
885
+ predicate specified either by its string name, or in the same
886
+ format as passed to
887
+ :meth:`~pymongo.collection.Collection.create_index` (e.g.
888
+ ``[('field', ASCENDING)]``). This option is only supported on
889
+ MongoDB 4.2 and above.
890
+ - `session` (optional): a
891
+ :class:`~pymongo.client_session.ClientSession`.
892
+ - `let` (optional): Map of parameter names and values. Values must be
893
+ constant or closed expressions that do not reference document
894
+ fields. Parameters can then be accessed as variables in an
895
+ aggregate expression context (e.g. "$$var").
896
+ - `comment` (optional): A user-provided comment to attach to this
897
+ command.
898
+ :Returns:
899
+ - An instance of :class:`~pymongo.results.UpdateResult`.
900
+
901
+ .. versionchanged:: 4.1
902
+ Added ``let`` parameter.
903
+ Added ``comment`` parameter.
904
+ .. versionchanged:: 3.11
905
+ Added ``hint`` parameter.
906
+ .. versionchanged:: 3.6
907
+ Added ``session`` parameter.
908
+ .. versionchanged:: 3.4
909
+ Added the `collation` option.
910
+ .. versionchanged:: 3.2
911
+ Added bypass_document_validation support.
912
+
913
+ .. versionadded:: 3.0
914
+ """
915
+ common.validate_is_mapping("filter", filter)
916
+ common.validate_ok_for_replace(replacement)
917
+ if let is not None:
918
+ common.validate_is_mapping("let", let)
919
+ write_concern = self._write_concern_for(session)
920
+ return UpdateResult(
921
+ self._update_retryable(
922
+ filter,
923
+ replacement,
924
+ upsert,
925
+ write_concern=write_concern,
926
+ bypass_doc_val=bypass_document_validation,
927
+ collation=collation,
928
+ hint=hint,
929
+ session=session,
930
+ let=let,
931
+ comment=comment,
932
+ ),
933
+ write_concern.acknowledged,
934
+ )
935
+
936
+ def update_one(
937
+ self,
938
+ filter: Mapping[str, Any],
939
+ update: Union[Mapping[str, Any], _Pipeline],
940
+ upsert: bool = False,
941
+ bypass_document_validation: bool = False,
942
+ collation: Optional[_CollationIn] = None,
943
+ array_filters: Optional[Sequence[Mapping[str, Any]]] = None,
944
+ hint: Optional[_IndexKeyHint] = None,
945
+ session: Optional["ClientSession"] = None,
946
+ let: Optional[Mapping[str, Any]] = None,
947
+ comment: Optional[Any] = None,
948
+ ) -> UpdateResult:
949
+ """Update a single document matching the filter.
950
+
951
+ >>> for doc in db.test.find():
952
+ ... print(doc)
953
+ ...
954
+ {'x': 1, '_id': 0}
955
+ {'x': 1, '_id': 1}
956
+ {'x': 1, '_id': 2}
957
+ >>> result = db.test.update_one({'x': 1}, {'$inc': {'x': 3}})
958
+ >>> result.matched_count
959
+ 1
960
+ >>> result.modified_count
961
+ 1
962
+ >>> for doc in db.test.find():
963
+ ... print(doc)
964
+ ...
965
+ {'x': 4, '_id': 0}
966
+ {'x': 1, '_id': 1}
967
+ {'x': 1, '_id': 2}
968
+
969
+ If ``upsert=True`` and no documents match the filter, create a
970
+ new document based on the filter criteria and update modifications.
971
+
972
+ >>> result = db.test.update_one({'x': -10}, {'$inc': {'x': 3}}, upsert=True)
973
+ >>> result.matched_count
974
+ 0
975
+ >>> result.modified_count
976
+ 0
977
+ >>> result.upserted_id
978
+ ObjectId('626a678eeaa80587d4bb3fb7')
979
+ >>> db.test.find_one(result.upserted_id)
980
+ {'_id': ObjectId('626a678eeaa80587d4bb3fb7'), 'x': -7}
981
+
982
+ :Parameters:
983
+ - `filter`: A query that matches the document to update.
984
+ - `update`: The modifications to apply.
985
+ - `upsert` (optional): If ``True``, perform an insert if no documents
986
+ match the filter.
987
+ - `bypass_document_validation`: (optional) If ``True``, allows the
988
+ write to opt-out of document level validation. Default is
989
+ ``False``.
990
+ - `collation` (optional): An instance of
991
+ :class:`~pymongo.collation.Collation`.
992
+ - `array_filters` (optional): A list of filters specifying which
993
+ array elements an update should apply.
994
+ - `hint` (optional): An index to use to support the query
995
+ predicate specified either by its string name, or in the same
996
+ format as passed to
997
+ :meth:`~pymongo.collection.Collection.create_index` (e.g.
998
+ ``[('field', ASCENDING)]``). This option is only supported on
999
+ MongoDB 4.2 and above.
1000
+ - `session` (optional): a
1001
+ :class:`~pymongo.client_session.ClientSession`.
1002
+ - `let` (optional): Map of parameter names and values. Values must be
1003
+ constant or closed expressions that do not reference document
1004
+ fields. Parameters can then be accessed as variables in an
1005
+ aggregate expression context (e.g. "$$var").
1006
+ - `comment` (optional): A user-provided comment to attach to this
1007
+ command.
1008
+
1009
+ :Returns:
1010
+ - An instance of :class:`~pymongo.results.UpdateResult`.
1011
+
1012
+ .. versionchanged:: 4.1
1013
+ Added ``let`` parameter.
1014
+ Added ``comment`` parameter.
1015
+ .. versionchanged:: 3.11
1016
+ Added ``hint`` parameter.
1017
+ .. versionchanged:: 3.9
1018
+ Added the ability to accept a pipeline as the ``update``.
1019
+ .. versionchanged:: 3.6
1020
+ Added the ``array_filters`` and ``session`` parameters.
1021
+ .. versionchanged:: 3.4
1022
+ Added the ``collation`` option.
1023
+ .. versionchanged:: 3.2
1024
+ Added ``bypass_document_validation`` support.
1025
+
1026
+ .. versionadded:: 3.0
1027
+ """
1028
+ common.validate_is_mapping("filter", filter)
1029
+ common.validate_ok_for_update(update)
1030
+ common.validate_list_or_none("array_filters", array_filters)
1031
+
1032
+ write_concern = self._write_concern_for(session)
1033
+ return UpdateResult(
1034
+ self._update_retryable(
1035
+ filter,
1036
+ update,
1037
+ upsert,
1038
+ write_concern=write_concern,
1039
+ bypass_doc_val=bypass_document_validation,
1040
+ collation=collation,
1041
+ array_filters=array_filters,
1042
+ hint=hint,
1043
+ session=session,
1044
+ let=let,
1045
+ comment=comment,
1046
+ ),
1047
+ write_concern.acknowledged,
1048
+ )
1049
+
1050
+ def update_many(
1051
+ self,
1052
+ filter: Mapping[str, Any],
1053
+ update: Union[Mapping[str, Any], _Pipeline],
1054
+ upsert: bool = False,
1055
+ array_filters: Optional[Sequence[Mapping[str, Any]]] = None,
1056
+ bypass_document_validation: Optional[bool] = None,
1057
+ collation: Optional[_CollationIn] = None,
1058
+ hint: Optional[_IndexKeyHint] = None,
1059
+ session: Optional["ClientSession"] = None,
1060
+ let: Optional[Mapping[str, Any]] = None,
1061
+ comment: Optional[Any] = None,
1062
+ ) -> UpdateResult:
1063
+ """Update one or more documents that match the filter.
1064
+
1065
+ >>> for doc in db.test.find():
1066
+ ... print(doc)
1067
+ ...
1068
+ {'x': 1, '_id': 0}
1069
+ {'x': 1, '_id': 1}
1070
+ {'x': 1, '_id': 2}
1071
+ >>> result = db.test.update_many({'x': 1}, {'$inc': {'x': 3}})
1072
+ >>> result.matched_count
1073
+ 3
1074
+ >>> result.modified_count
1075
+ 3
1076
+ >>> for doc in db.test.find():
1077
+ ... print(doc)
1078
+ ...
1079
+ {'x': 4, '_id': 0}
1080
+ {'x': 4, '_id': 1}
1081
+ {'x': 4, '_id': 2}
1082
+
1083
+ :Parameters:
1084
+ - `filter`: A query that matches the documents to update.
1085
+ - `update`: The modifications to apply.
1086
+ - `upsert` (optional): If ``True``, perform an insert if no documents
1087
+ match the filter.
1088
+ - `bypass_document_validation` (optional): If ``True``, allows the
1089
+ write to opt-out of document level validation. Default is
1090
+ ``False``.
1091
+ - `collation` (optional): An instance of
1092
+ :class:`~pymongo.collation.Collation`.
1093
+ - `array_filters` (optional): A list of filters specifying which
1094
+ array elements an update should apply.
1095
+ - `hint` (optional): An index to use to support the query
1096
+ predicate specified either by its string name, or in the same
1097
+ format as passed to
1098
+ :meth:`~pymongo.collection.Collection.create_index` (e.g.
1099
+ ``[('field', ASCENDING)]``). This option is only supported on
1100
+ MongoDB 4.2 and above.
1101
+ - `session` (optional): a
1102
+ :class:`~pymongo.client_session.ClientSession`.
1103
+ - `let` (optional): Map of parameter names and values. Values must be
1104
+ constant or closed expressions that do not reference document
1105
+ fields. Parameters can then be accessed as variables in an
1106
+ aggregate expression context (e.g. "$$var").
1107
+ - `comment` (optional): A user-provided comment to attach to this
1108
+ command.
1109
+
1110
+ :Returns:
1111
+ - An instance of :class:`~pymongo.results.UpdateResult`.
1112
+
1113
+ .. versionchanged:: 4.1
1114
+ Added ``let`` parameter.
1115
+ Added ``comment`` parameter.
1116
+ .. versionchanged:: 3.11
1117
+ Added ``hint`` parameter.
1118
+ .. versionchanged:: 3.9
1119
+ Added the ability to accept a pipeline as the `update`.
1120
+ .. versionchanged:: 3.6
1121
+ Added ``array_filters`` and ``session`` parameters.
1122
+ .. versionchanged:: 3.4
1123
+ Added the `collation` option.
1124
+ .. versionchanged:: 3.2
1125
+ Added bypass_document_validation support.
1126
+
1127
+ .. versionadded:: 3.0
1128
+ """
1129
+ common.validate_is_mapping("filter", filter)
1130
+ common.validate_ok_for_update(update)
1131
+ common.validate_list_or_none("array_filters", array_filters)
1132
+
1133
+ write_concern = self._write_concern_for(session)
1134
+ return UpdateResult(
1135
+ self._update_retryable(
1136
+ filter,
1137
+ update,
1138
+ upsert,
1139
+ multi=True,
1140
+ write_concern=write_concern,
1141
+ bypass_doc_val=bypass_document_validation,
1142
+ collation=collation,
1143
+ array_filters=array_filters,
1144
+ hint=hint,
1145
+ session=session,
1146
+ let=let,
1147
+ comment=comment,
1148
+ ),
1149
+ write_concern.acknowledged,
1150
+ )
1151
+
1152
+ def drop(
1153
+ self,
1154
+ session: Optional["ClientSession"] = None,
1155
+ comment: Optional[Any] = None,
1156
+ encrypted_fields: Optional[Mapping[str, Any]] = None,
1157
+ ) -> None:
1158
+ """Alias for :meth:`~pymongo.database.Database.drop_collection`.
1159
+
1160
+ :Parameters:
1161
+ - `session` (optional): a
1162
+ :class:`~pymongo.client_session.ClientSession`.
1163
+ - `comment` (optional): A user-provided comment to attach to this
1164
+ command.
1165
+ - `encrypted_fields`: **(BETA)** Document that describes the encrypted fields for
1166
+ Queryable Encryption.
1167
+
1168
+ The following two calls are equivalent:
1169
+
1170
+ >>> db.foo.drop()
1171
+ >>> db.drop_collection("foo")
1172
+
1173
+ .. versionchanged:: 4.2
1174
+ Added ``encrypted_fields`` parameter.
1175
+
1176
+ .. versionchanged:: 4.1
1177
+ Added ``comment`` parameter.
1178
+
1179
+ .. versionchanged:: 3.7
1180
+ :meth:`drop` now respects this :class:`Collection`'s :attr:`write_concern`.
1181
+
1182
+ .. versionchanged:: 3.6
1183
+ Added ``session`` parameter.
1184
+ """
1185
+ dbo = self.__database.client.get_database(
1186
+ self.__database.name,
1187
+ self.codec_options,
1188
+ self.read_preference,
1189
+ self.write_concern,
1190
+ self.read_concern,
1191
+ )
1192
+ dbo.drop_collection(
1193
+ self.__name, session=session, comment=comment, encrypted_fields=encrypted_fields
1194
+ )
1195
+
1196
+ def _delete(
1197
+ self,
1198
+ sock_info,
1199
+ criteria,
1200
+ multi,
1201
+ write_concern=None,
1202
+ op_id=None,
1203
+ ordered=True,
1204
+ collation=None,
1205
+ hint=None,
1206
+ session=None,
1207
+ retryable_write=False,
1208
+ let=None,
1209
+ comment=None,
1210
+ ):
1211
+ """Internal delete helper."""
1212
+ common.validate_is_mapping("filter", criteria)
1213
+ write_concern = write_concern or self.write_concern
1214
+ acknowledged = write_concern.acknowledged
1215
+ delete_doc = SON([("q", criteria), ("limit", int(not multi))])
1216
+ collation = validate_collation_or_none(collation)
1217
+ if collation is not None:
1218
+ if not acknowledged:
1219
+ raise ConfigurationError("Collation is unsupported for unacknowledged writes.")
1220
+ else:
1221
+ delete_doc["collation"] = collation
1222
+ if hint is not None:
1223
+ if not acknowledged and sock_info.max_wire_version < 9:
1224
+ raise ConfigurationError(
1225
+ "Must be connected to MongoDB 4.4+ to use hint on unacknowledged delete commands."
1226
+ )
1227
+ if not isinstance(hint, str):
1228
+ hint = helpers._index_document(hint)
1229
+ delete_doc["hint"] = hint
1230
+ command = SON([("delete", self.name), ("ordered", ordered), ("deletes", [delete_doc])])
1231
+
1232
+ if let is not None:
1233
+ common.validate_is_document_type("let", let)
1234
+ command["let"] = let
1235
+
1236
+ if comment is not None:
1237
+ command["comment"] = comment
1238
+
1239
+ # Delete command.
1240
+ result = sock_info.command(
1241
+ self.__database.name,
1242
+ command,
1243
+ write_concern=write_concern,
1244
+ codec_options=self.__write_response_codec_options,
1245
+ session=session,
1246
+ client=self.__database.client,
1247
+ retryable_write=retryable_write,
1248
+ )
1249
+ _check_write_command_response(result)
1250
+ return result
1251
+
1252
+ def _delete_retryable(
1253
+ self,
1254
+ criteria,
1255
+ multi,
1256
+ write_concern=None,
1257
+ op_id=None,
1258
+ ordered=True,
1259
+ collation=None,
1260
+ hint=None,
1261
+ session=None,
1262
+ let=None,
1263
+ comment=None,
1264
+ ):
1265
+ """Internal delete helper."""
1266
+
1267
+ def _delete(session, sock_info, retryable_write):
1268
+ return self._delete(
1269
+ sock_info,
1270
+ criteria,
1271
+ multi,
1272
+ write_concern=write_concern,
1273
+ op_id=op_id,
1274
+ ordered=ordered,
1275
+ collation=collation,
1276
+ hint=hint,
1277
+ session=session,
1278
+ retryable_write=retryable_write,
1279
+ let=let,
1280
+ comment=comment,
1281
+ )
1282
+
1283
+ return self.__database.client._retryable_write(
1284
+ (write_concern or self.write_concern).acknowledged and not multi, _delete, session
1285
+ )
1286
+
1287
+ def delete_one(
1288
+ self,
1289
+ filter: Mapping[str, Any],
1290
+ collation: Optional[_CollationIn] = None,
1291
+ hint: Optional[_IndexKeyHint] = None,
1292
+ session: Optional["ClientSession"] = None,
1293
+ let: Optional[Mapping[str, Any]] = None,
1294
+ comment: Optional[Any] = None,
1295
+ ) -> DeleteResult:
1296
+ """Delete a single document matching the filter.
1297
+
1298
+ >>> db.test.count_documents({'x': 1})
1299
+ 3
1300
+ >>> result = db.test.delete_one({'x': 1})
1301
+ >>> result.deleted_count
1302
+ 1
1303
+ >>> db.test.count_documents({'x': 1})
1304
+ 2
1305
+
1306
+ :Parameters:
1307
+ - `filter`: A query that matches the document to delete.
1308
+ - `collation` (optional): An instance of
1309
+ :class:`~pymongo.collation.Collation`.
1310
+ - `hint` (optional): An index to use to support the query
1311
+ predicate specified either by its string name, or in the same
1312
+ format as passed to
1313
+ :meth:`~pymongo.collection.Collection.create_index` (e.g.
1314
+ ``[('field', ASCENDING)]``). This option is only supported on
1315
+ MongoDB 4.4 and above.
1316
+ - `session` (optional): a
1317
+ :class:`~pymongo.client_session.ClientSession`.
1318
+ - `let` (optional): Map of parameter names and values. Values must be
1319
+ constant or closed expressions that do not reference document
1320
+ fields. Parameters can then be accessed as variables in an
1321
+ aggregate expression context (e.g. "$$var").
1322
+ - `comment` (optional): A user-provided comment to attach to this
1323
+ command.
1324
+
1325
+ :Returns:
1326
+ - An instance of :class:`~pymongo.results.DeleteResult`.
1327
+
1328
+ .. versionchanged:: 4.1
1329
+ Added ``let`` parameter.
1330
+ Added ``comment`` parameter.
1331
+ .. versionchanged:: 3.11
1332
+ Added ``hint`` parameter.
1333
+ .. versionchanged:: 3.6
1334
+ Added ``session`` parameter.
1335
+ .. versionchanged:: 3.4
1336
+ Added the `collation` option.
1337
+ .. versionadded:: 3.0
1338
+ """
1339
+ write_concern = self._write_concern_for(session)
1340
+ return DeleteResult(
1341
+ self._delete_retryable(
1342
+ filter,
1343
+ False,
1344
+ write_concern=write_concern,
1345
+ collation=collation,
1346
+ hint=hint,
1347
+ session=session,
1348
+ let=let,
1349
+ comment=comment,
1350
+ ),
1351
+ write_concern.acknowledged,
1352
+ )
1353
+
1354
+ def delete_many(
1355
+ self,
1356
+ filter: Mapping[str, Any],
1357
+ collation: Optional[_CollationIn] = None,
1358
+ hint: Optional[_IndexKeyHint] = None,
1359
+ session: Optional["ClientSession"] = None,
1360
+ let: Optional[Mapping[str, Any]] = None,
1361
+ comment: Optional[Any] = None,
1362
+ ) -> DeleteResult:
1363
+ """Delete one or more documents matching the filter.
1364
+
1365
+ >>> db.test.count_documents({'x': 1})
1366
+ 3
1367
+ >>> result = db.test.delete_many({'x': 1})
1368
+ >>> result.deleted_count
1369
+ 3
1370
+ >>> db.test.count_documents({'x': 1})
1371
+ 0
1372
+
1373
+ :Parameters:
1374
+ - `filter`: A query that matches the documents to delete.
1375
+ - `collation` (optional): An instance of
1376
+ :class:`~pymongo.collation.Collation`.
1377
+ - `hint` (optional): An index to use to support the query
1378
+ predicate specified either by its string name, or in the same
1379
+ format as passed to
1380
+ :meth:`~pymongo.collection.Collection.create_index` (e.g.
1381
+ ``[('field', ASCENDING)]``). This option is only supported on
1382
+ MongoDB 4.4 and above.
1383
+ - `session` (optional): a
1384
+ :class:`~pymongo.client_session.ClientSession`.
1385
+ - `let` (optional): Map of parameter names and values. Values must be
1386
+ constant or closed expressions that do not reference document
1387
+ fields. Parameters can then be accessed as variables in an
1388
+ aggregate expression context (e.g. "$$var").
1389
+ - `comment` (optional): A user-provided comment to attach to this
1390
+ command.
1391
+
1392
+ :Returns:
1393
+ - An instance of :class:`~pymongo.results.DeleteResult`.
1394
+
1395
+ .. versionchanged:: 4.1
1396
+ Added ``let`` parameter.
1397
+ Added ``comment`` parameter.
1398
+ .. versionchanged:: 3.11
1399
+ Added ``hint`` parameter.
1400
+ .. versionchanged:: 3.6
1401
+ Added ``session`` parameter.
1402
+ .. versionchanged:: 3.4
1403
+ Added the `collation` option.
1404
+ .. versionadded:: 3.0
1405
+ """
1406
+ write_concern = self._write_concern_for(session)
1407
+ return DeleteResult(
1408
+ self._delete_retryable(
1409
+ filter,
1410
+ True,
1411
+ write_concern=write_concern,
1412
+ collation=collation,
1413
+ hint=hint,
1414
+ session=session,
1415
+ let=let,
1416
+ comment=comment,
1417
+ ),
1418
+ write_concern.acknowledged,
1419
+ )
1420
+
1421
+ def find_one(
1422
+ self, filter: Optional[Any] = None, *args: Any, **kwargs: Any
1423
+ ) -> Optional[_DocumentType]:
1424
+ """Get a single document from the database.
1425
+
1426
+ All arguments to :meth:`find` are also valid arguments for
1427
+ :meth:`find_one`, although any `limit` argument will be
1428
+ ignored. Returns a single document, or ``None`` if no matching
1429
+ document is found.
1430
+
1431
+ The :meth:`find_one` method obeys the :attr:`read_preference` of
1432
+ this :class:`Collection`.
1433
+
1434
+ :Parameters:
1435
+
1436
+ - `filter` (optional): a dictionary specifying
1437
+ the query to be performed OR any other type to be used as
1438
+ the value for a query for ``"_id"``.
1439
+
1440
+ - `*args` (optional): any additional positional arguments
1441
+ are the same as the arguments to :meth:`find`.
1442
+
1443
+ - `**kwargs` (optional): any additional keyword arguments
1444
+ are the same as the arguments to :meth:`find`.
1445
+
1446
+ >>> collection.find_one(max_time_ms=100)
1447
+
1448
+ """
1449
+ if filter is not None and not isinstance(filter, abc.Mapping):
1450
+ filter = {"_id": filter}
1451
+ cursor = self.find(filter, *args, **kwargs)
1452
+ for result in cursor.limit(-1):
1453
+ return result
1454
+ return None
1455
+
1456
+ def find(self, *args: Any, **kwargs: Any) -> Cursor[_DocumentType]:
1457
+ """Query the database.
1458
+
1459
+ The `filter` argument is a query document that all results
1460
+ must match. For example:
1461
+
1462
+ >>> db.test.find({"hello": "world"})
1463
+
1464
+ only matches documents that have a key "hello" with value
1465
+ "world". Matches can have other keys *in addition* to
1466
+ "hello". The `projection` argument is used to specify a subset
1467
+ of fields that should be included in the result documents. By
1468
+ limiting results to a certain subset of fields you can cut
1469
+ down on network traffic and decoding time.
1470
+
1471
+ Raises :class:`TypeError` if any of the arguments are of
1472
+ improper type. Returns an instance of
1473
+ :class:`~pymongo.cursor.Cursor` corresponding to this query.
1474
+
1475
+ The :meth:`find` method obeys the :attr:`read_preference` of
1476
+ this :class:`Collection`.
1477
+
1478
+ :Parameters:
1479
+ - `filter` (optional): A query document that selects which documents
1480
+ to include in the result set. Can be an empty document to include
1481
+ all documents.
1482
+ - `projection` (optional): a list of field names that should be
1483
+ returned in the result set or a dict specifying the fields
1484
+ to include or exclude. If `projection` is a list "_id" will
1485
+ always be returned. Use a dict to exclude fields from
1486
+ the result (e.g. projection={'_id': False}).
1487
+ - `session` (optional): a
1488
+ :class:`~pymongo.client_session.ClientSession`.
1489
+ - `skip` (optional): the number of documents to omit (from
1490
+ the start of the result set) when returning the results
1491
+ - `limit` (optional): the maximum number of results to
1492
+ return. A limit of 0 (the default) is equivalent to setting no
1493
+ limit.
1494
+ - `no_cursor_timeout` (optional): if False (the default), any
1495
+ returned cursor is closed by the server after 10 minutes of
1496
+ inactivity. If set to True, the returned cursor will never
1497
+ time out on the server. Care should be taken to ensure that
1498
+ cursors with no_cursor_timeout turned on are properly closed.
1499
+ - `cursor_type` (optional): the type of cursor to return. The valid
1500
+ options are defined by :class:`~pymongo.cursor.CursorType`:
1501
+
1502
+ - :attr:`~pymongo.cursor.CursorType.NON_TAILABLE` - the result of
1503
+ this find call will return a standard cursor over the result set.
1504
+ - :attr:`~pymongo.cursor.CursorType.TAILABLE` - the result of this
1505
+ find call will be a tailable cursor - tailable cursors are only
1506
+ for use with capped collections. They are not closed when the
1507
+ last data is retrieved but are kept open and the cursor location
1508
+ marks the final document position. If more data is received
1509
+ iteration of the cursor will continue from the last document
1510
+ received. For details, see the `tailable cursor documentation
1511
+ <https://www.mongodb.com/docs/manual/core/tailable-cursors/>`_.
1512
+ - :attr:`~pymongo.cursor.CursorType.TAILABLE_AWAIT` - the result
1513
+ of this find call will be a tailable cursor with the await flag
1514
+ set. The server will wait for a few seconds after returning the
1515
+ full result set so that it can capture and return additional data
1516
+ added during the query.
1517
+ - :attr:`~pymongo.cursor.CursorType.EXHAUST` - the result of this
1518
+ find call will be an exhaust cursor. MongoDB will stream batched
1519
+ results to the client without waiting for the client to request
1520
+ each batch, reducing latency. See notes on compatibility below.
1521
+
1522
+ - `sort` (optional): a list of (key, direction) pairs
1523
+ specifying the sort order for this query. See
1524
+ :meth:`~pymongo.cursor.Cursor.sort` for details.
1525
+ - `allow_partial_results` (optional): if True, mongos will return
1526
+ partial results if some shards are down instead of returning an
1527
+ error.
1528
+ - `oplog_replay` (optional): **DEPRECATED** - if True, set the
1529
+ oplogReplay query flag. Default: False.
1530
+ - `batch_size` (optional): Limits the number of documents returned in
1531
+ a single batch.
1532
+ - `collation` (optional): An instance of
1533
+ :class:`~pymongo.collation.Collation`.
1534
+ - `return_key` (optional): If True, return only the index keys in
1535
+ each document.
1536
+ - `show_record_id` (optional): If True, adds a field ``$recordId`` in
1537
+ each document with the storage engine's internal record identifier.
1538
+ - `snapshot` (optional): **DEPRECATED** - If True, prevents the
1539
+ cursor from returning a document more than once because of an
1540
+ intervening write operation.
1541
+ - `hint` (optional): An index, in the same format as passed to
1542
+ :meth:`~pymongo.collection.Collection.create_index` (e.g.
1543
+ ``[('field', ASCENDING)]``). Pass this as an alternative to calling
1544
+ :meth:`~pymongo.cursor.Cursor.hint` on the cursor to tell Mongo the
1545
+ proper index to use for the query.
1546
+ - `max_time_ms` (optional): Specifies a time limit for a query
1547
+ operation. If the specified time is exceeded, the operation will be
1548
+ aborted and :exc:`~pymongo.errors.ExecutionTimeout` is raised. Pass
1549
+ this as an alternative to calling
1550
+ :meth:`~pymongo.cursor.Cursor.max_time_ms` on the cursor.
1551
+ - `max_scan` (optional): **DEPRECATED** - The maximum number of
1552
+ documents to scan. Pass this as an alternative to calling
1553
+ :meth:`~pymongo.cursor.Cursor.max_scan` on the cursor.
1554
+ - `min` (optional): A list of field, limit pairs specifying the
1555
+ inclusive lower bound for all keys of a specific index in order.
1556
+ Pass this as an alternative to calling
1557
+ :meth:`~pymongo.cursor.Cursor.min` on the cursor. ``hint`` must
1558
+ also be passed to ensure the query utilizes the correct index.
1559
+ - `max` (optional): A list of field, limit pairs specifying the
1560
+ exclusive upper bound for all keys of a specific index in order.
1561
+ Pass this as an alternative to calling
1562
+ :meth:`~pymongo.cursor.Cursor.max` on the cursor. ``hint`` must
1563
+ also be passed to ensure the query utilizes the correct index.
1564
+ - `comment` (optional): A string to attach to the query to help
1565
+ interpret and trace the operation in the server logs and in profile
1566
+ data. Pass this as an alternative to calling
1567
+ :meth:`~pymongo.cursor.Cursor.comment` on the cursor.
1568
+ - `allow_disk_use` (optional): if True, MongoDB may use temporary
1569
+ disk files to store data exceeding the system memory limit while
1570
+ processing a blocking sort operation. The option has no effect if
1571
+ MongoDB can satisfy the specified sort using an index, or if the
1572
+ blocking sort requires less memory than the 100 MiB limit. This
1573
+ option is only supported on MongoDB 4.4 and above.
1574
+
1575
+ .. note:: There are a number of caveats to using
1576
+ :attr:`~pymongo.cursor.CursorType.EXHAUST` as cursor_type:
1577
+
1578
+ - The `limit` option can not be used with an exhaust cursor.
1579
+
1580
+ - Exhaust cursors are not supported by mongos and can not be
1581
+ used with a sharded cluster.
1582
+
1583
+ - A :class:`~pymongo.cursor.Cursor` instance created with the
1584
+ :attr:`~pymongo.cursor.CursorType.EXHAUST` cursor_type requires an
1585
+ exclusive :class:`~socket.socket` connection to MongoDB. If the
1586
+ :class:`~pymongo.cursor.Cursor` is discarded without being
1587
+ completely iterated the underlying :class:`~socket.socket`
1588
+ connection will be closed and discarded without being returned to
1589
+ the connection pool.
1590
+
1591
+ .. versionchanged:: 4.0
1592
+ Removed the ``modifiers`` option.
1593
+ Empty projections (eg {} or []) are passed to the server as-is,
1594
+ rather than the previous behavior which substituted in a
1595
+ projection of ``{"_id": 1}``. This means that an empty projection
1596
+ will now return the entire document, not just the ``"_id"`` field.
1597
+
1598
+ .. versionchanged:: 3.11
1599
+ Added the ``allow_disk_use`` option.
1600
+ Deprecated the ``oplog_replay`` option. Support for this option is
1601
+ deprecated in MongoDB 4.4. The query engine now automatically
1602
+ optimizes queries against the oplog without requiring this
1603
+ option to be set.
1604
+
1605
+ .. versionchanged:: 3.7
1606
+ Deprecated the ``snapshot`` option, which is deprecated in MongoDB
1607
+ 3.6 and removed in MongoDB 4.0.
1608
+ Deprecated the ``max_scan`` option. Support for this option is
1609
+ deprecated in MongoDB 4.0. Use ``max_time_ms`` instead to limit
1610
+ server-side execution time.
1611
+
1612
+ .. versionchanged:: 3.6
1613
+ Added ``session`` parameter.
1614
+
1615
+ .. versionchanged:: 3.5
1616
+ Added the options ``return_key``, ``show_record_id``, ``snapshot``,
1617
+ ``hint``, ``max_time_ms``, ``max_scan``, ``min``, ``max``, and
1618
+ ``comment``.
1619
+ Deprecated the ``modifiers`` option.
1620
+
1621
+ .. versionchanged:: 3.4
1622
+ Added support for the ``collation`` option.
1623
+
1624
+ .. versionchanged:: 3.0
1625
+ Changed the parameter names ``spec``, ``fields``, ``timeout``, and
1626
+ ``partial`` to ``filter``, ``projection``, ``no_cursor_timeout``,
1627
+ and ``allow_partial_results`` respectively.
1628
+ Added the ``cursor_type``, ``oplog_replay``, and ``modifiers``
1629
+ options.
1630
+ Removed the ``network_timeout``, ``read_preference``, ``tag_sets``,
1631
+ ``secondary_acceptable_latency_ms``, ``max_scan``, ``snapshot``,
1632
+ ``tailable``, ``await_data``, ``exhaust``, ``as_class``, and
1633
+ slave_okay parameters.
1634
+ Removed ``compile_re`` option: PyMongo now always
1635
+ represents BSON regular expressions as :class:`~bson.regex.Regex`
1636
+ objects. Use :meth:`~bson.regex.Regex.try_compile` to attempt to
1637
+ convert from a BSON regular expression to a Python regular
1638
+ expression object.
1639
+ Soft deprecated the ``manipulate`` option.
1640
+
1641
+ .. seealso:: The MongoDB documentation on `find <https://dochub.mongodb.org/core/find>`_.
1642
+ """
1643
+ return Cursor(self, *args, **kwargs)
1644
+
1645
+ def find_raw_batches(self, *args: Any, **kwargs: Any) -> RawBatchCursor[_DocumentType]:
1646
+ """Query the database and retrieve batches of raw BSON.
1647
+
1648
+ Similar to the :meth:`find` method but returns a
1649
+ :class:`~pymongo.cursor.RawBatchCursor`.
1650
+
1651
+ This example demonstrates how to work with raw batches, but in practice
1652
+ raw batches should be passed to an external library that can decode
1653
+ BSON into another data type, rather than used with PyMongo's
1654
+ :mod:`bson` module.
1655
+
1656
+ >>> import bson
1657
+ >>> cursor = db.test.find_raw_batches()
1658
+ >>> for batch in cursor:
1659
+ ... print(bson.decode_all(batch))
1660
+
1661
+ .. note:: find_raw_batches does not support auto encryption.
1662
+
1663
+ .. versionchanged:: 3.12
1664
+ Instead of ignoring the user-specified read concern, this method
1665
+ now sends it to the server when connected to MongoDB 3.6+.
1666
+
1667
+ Added session support.
1668
+
1669
+ .. versionadded:: 3.6
1670
+ """
1671
+ # OP_MSG is required to support encryption.
1672
+ if self.__database.client._encrypter:
1673
+ raise InvalidOperation("find_raw_batches does not support auto encryption")
1674
+ return RawBatchCursor(self, *args, **kwargs)
1675
+
1676
+ def _count_cmd(self, session, sock_info, read_preference, cmd, collation):
1677
+ """Internal count command helper."""
1678
+ # XXX: "ns missing" checks can be removed when we drop support for
1679
+ # MongoDB 3.0, see SERVER-17051.
1680
+ res = self._command(
1681
+ sock_info,
1682
+ cmd,
1683
+ read_preference=read_preference,
1684
+ allowable_errors=["ns missing"],
1685
+ codec_options=self.__write_response_codec_options,
1686
+ read_concern=self.read_concern,
1687
+ collation=collation,
1688
+ session=session,
1689
+ )
1690
+ if res.get("errmsg", "") == "ns missing":
1691
+ return 0
1692
+ return int(res["n"])
1693
+
1694
+ def _aggregate_one_result(self, sock_info, read_preference, cmd, collation, session):
1695
+ """Internal helper to run an aggregate that returns a single result."""
1696
+ result = self._command(
1697
+ sock_info,
1698
+ cmd,
1699
+ read_preference,
1700
+ allowable_errors=[26], # Ignore NamespaceNotFound.
1701
+ codec_options=self.__write_response_codec_options,
1702
+ read_concern=self.read_concern,
1703
+ collation=collation,
1704
+ session=session,
1705
+ )
1706
+ # cursor will not be present for NamespaceNotFound errors.
1707
+ if "cursor" not in result:
1708
+ return None
1709
+ batch = result["cursor"]["firstBatch"]
1710
+ return batch[0] if batch else None
1711
+
1712
+ def estimated_document_count(self, comment: Optional[Any] = None, **kwargs: Any) -> int:
1713
+ """Get an estimate of the number of documents in this collection using
1714
+ collection metadata.
1715
+
1716
+ The :meth:`estimated_document_count` method is **not** supported in a
1717
+ transaction.
1718
+
1719
+ All optional parameters should be passed as keyword arguments
1720
+ to this method. Valid options include:
1721
+
1722
+ - `maxTimeMS` (int): The maximum amount of time to allow this
1723
+ operation to run, in milliseconds.
1724
+
1725
+ :Parameters:
1726
+ - `comment` (optional): A user-provided comment to attach to this
1727
+ command.
1728
+ - `**kwargs` (optional): See list of options above.
1729
+
1730
+ .. versionchanged:: 4.2
1731
+ This method now always uses the `count`_ command. Due to an oversight in versions
1732
+ 5.0.0-5.0.8 of MongoDB, the count command was not included in V1 of the
1733
+ :ref:`versioned-api-ref`. Users of the Stable API with estimated_document_count are
1734
+ recommended to upgrade their server version to 5.0.9+ or set
1735
+ :attr:`pymongo.server_api.ServerApi.strict` to ``False`` to avoid encountering errors.
1736
+
1737
+ .. versionadded:: 3.7
1738
+ .. _count: https://mongodb.com/docs/manual/reference/command/count/
1739
+ """
1740
+ if "session" in kwargs:
1741
+ raise ConfigurationError("estimated_document_count does not support sessions")
1742
+ if comment is not None:
1743
+ kwargs["comment"] = comment
1744
+
1745
+ def _cmd(session, server, sock_info, read_preference):
1746
+ cmd = SON([("count", self.__name)])
1747
+ cmd.update(kwargs)
1748
+ return self._count_cmd(session, sock_info, read_preference, cmd, collation=None)
1749
+
1750
+ return self._retryable_non_cursor_read(_cmd, None)
1751
+
1752
+ def count_documents(
1753
+ self,
1754
+ filter: Mapping[str, Any],
1755
+ session: Optional["ClientSession"] = None,
1756
+ comment: Optional[Any] = None,
1757
+ **kwargs: Any,
1758
+ ) -> int:
1759
+ """Count the number of documents in this collection.
1760
+
1761
+ .. note:: For a fast count of the total documents in a collection see
1762
+ :meth:`estimated_document_count`.
1763
+
1764
+ The :meth:`count_documents` method is supported in a transaction.
1765
+
1766
+ All optional parameters should be passed as keyword arguments
1767
+ to this method. Valid options include:
1768
+
1769
+ - `skip` (int): The number of matching documents to skip before
1770
+ returning results.
1771
+ - `limit` (int): The maximum number of documents to count. Must be
1772
+ a positive integer. If not provided, no limit is imposed.
1773
+ - `maxTimeMS` (int): The maximum amount of time to allow this
1774
+ operation to run, in milliseconds.
1775
+ - `collation` (optional): An instance of
1776
+ :class:`~pymongo.collation.Collation`.
1777
+ - `hint` (string or list of tuples): The index to use. Specify either
1778
+ the index name as a string or the index specification as a list of
1779
+ tuples (e.g. [('a', pymongo.ASCENDING), ('b', pymongo.ASCENDING)]).
1780
+
1781
+ The :meth:`count_documents` method obeys the :attr:`read_preference` of
1782
+ this :class:`Collection`.
1783
+
1784
+ .. note:: When migrating from :meth:`count` to :meth:`count_documents`
1785
+ the following query operators must be replaced:
1786
+
1787
+ +-------------+-------------------------------------+
1788
+ | Operator | Replacement |
1789
+ +=============+=====================================+
1790
+ | $where | `$expr`_ |
1791
+ +-------------+-------------------------------------+
1792
+ | $near | `$geoWithin`_ with `$center`_ |
1793
+ +-------------+-------------------------------------+
1794
+ | $nearSphere | `$geoWithin`_ with `$centerSphere`_ |
1795
+ +-------------+-------------------------------------+
1796
+
1797
+ :Parameters:
1798
+ - `filter` (required): A query document that selects which documents
1799
+ to count in the collection. Can be an empty document to count all
1800
+ documents.
1801
+ - `session` (optional): a
1802
+ :class:`~pymongo.client_session.ClientSession`.
1803
+ - `comment` (optional): A user-provided comment to attach to this
1804
+ command.
1805
+ - `**kwargs` (optional): See list of options above.
1806
+
1807
+
1808
+ .. versionadded:: 3.7
1809
+
1810
+ .. _$expr: https://mongodb.com/docs/manual/reference/operator/query/expr/
1811
+ .. _$geoWithin: https://mongodb.com/docs/manual/reference/operator/query/geoWithin/
1812
+ .. _$center: https://mongodb.com/docs/manual/reference/operator/query/center/
1813
+ .. _$centerSphere: https://mongodb.com/docs/manual/reference/operator/query/centerSphere/
1814
+ """
1815
+ pipeline = [{"$match": filter}]
1816
+ if "skip" in kwargs:
1817
+ pipeline.append({"$skip": kwargs.pop("skip")})
1818
+ if "limit" in kwargs:
1819
+ pipeline.append({"$limit": kwargs.pop("limit")})
1820
+ if comment is not None:
1821
+ kwargs["comment"] = comment
1822
+ pipeline.append({"$group": {"_id": 1, "n": {"$sum": 1}}})
1823
+ cmd = SON([("aggregate", self.__name), ("pipeline", pipeline), ("cursor", {})])
1824
+ if "hint" in kwargs and not isinstance(kwargs["hint"], str):
1825
+ kwargs["hint"] = helpers._index_document(kwargs["hint"])
1826
+ collation = validate_collation_or_none(kwargs.pop("collation", None))
1827
+ cmd.update(kwargs)
1828
+
1829
+ def _cmd(session, server, sock_info, read_preference):
1830
+ result = self._aggregate_one_result(sock_info, read_preference, cmd, collation, session)
1831
+ if not result:
1832
+ return 0
1833
+ return result["n"]
1834
+
1835
+ return self._retryable_non_cursor_read(_cmd, session)
1836
+
1837
+ def _retryable_non_cursor_read(self, func, session):
1838
+ """Non-cursor read helper to handle implicit session creation."""
1839
+ client = self.__database.client
1840
+ with client._tmp_session(session) as s:
1841
+ return client._retryable_read(func, self._read_preference_for(s), s)
1842
+
1843
+ def create_indexes(
1844
+ self,
1845
+ indexes: Sequence[IndexModel],
1846
+ session: Optional["ClientSession"] = None,
1847
+ comment: Optional[Any] = None,
1848
+ **kwargs: Any,
1849
+ ) -> List[str]:
1850
+ """Create one or more indexes on this collection.
1851
+
1852
+ >>> from pymongo import IndexModel, ASCENDING, DESCENDING
1853
+ >>> index1 = IndexModel([("hello", DESCENDING),
1854
+ ... ("world", ASCENDING)], name="hello_world")
1855
+ >>> index2 = IndexModel([("goodbye", DESCENDING)])
1856
+ >>> db.test.create_indexes([index1, index2])
1857
+ ["hello_world", "goodbye_-1"]
1858
+
1859
+ :Parameters:
1860
+ - `indexes`: A list of :class:`~pymongo.operations.IndexModel`
1861
+ instances.
1862
+ - `session` (optional): a
1863
+ :class:`~pymongo.client_session.ClientSession`.
1864
+ - `comment` (optional): A user-provided comment to attach to this
1865
+ command.
1866
+ - `**kwargs` (optional): optional arguments to the createIndexes
1867
+ command (like maxTimeMS) can be passed as keyword arguments.
1868
+
1869
+
1870
+
1871
+
1872
+ .. note:: The :attr:`~pymongo.collection.Collection.write_concern` of
1873
+ this collection is automatically applied to this operation.
1874
+
1875
+ .. versionchanged:: 3.6
1876
+ Added ``session`` parameter. Added support for arbitrary keyword
1877
+ arguments.
1878
+
1879
+ .. versionchanged:: 3.4
1880
+ Apply this collection's write concern automatically to this operation
1881
+ when connected to MongoDB >= 3.4.
1882
+ .. versionadded:: 3.0
1883
+
1884
+ .. _createIndexes: https://mongodb.com/docs/manual/reference/command/createIndexes/
1885
+ """
1886
+ common.validate_list("indexes", indexes)
1887
+ if comment is not None:
1888
+ kwargs["comment"] = comment
1889
+ return self.__create_indexes(indexes, session, **kwargs)
1890
+
1891
+ @_csot.apply
1892
+ def __create_indexes(self, indexes, session, **kwargs):
1893
+ """Internal createIndexes helper.
1894
+
1895
+ :Parameters:
1896
+ - `indexes`: A list of :class:`~pymongo.operations.IndexModel`
1897
+ instances.
1898
+ - `session` (optional): a
1899
+ :class:`~pymongo.client_session.ClientSession`.
1900
+ - `**kwargs` (optional): optional arguments to the createIndexes
1901
+ command (like maxTimeMS) can be passed as keyword arguments.
1902
+ """
1903
+ names = []
1904
+ with self._socket_for_writes(session) as sock_info:
1905
+ supports_quorum = sock_info.max_wire_version >= 9
1906
+
1907
+ def gen_indexes():
1908
+ for index in indexes:
1909
+ if not isinstance(index, IndexModel):
1910
+ raise TypeError(
1911
+ "%r is not an instance of pymongo.operations.IndexModel" % (index,)
1912
+ )
1913
+ document = index.document
1914
+ names.append(document["name"])
1915
+ yield document
1916
+
1917
+ cmd = SON([("createIndexes", self.name), ("indexes", list(gen_indexes()))])
1918
+ cmd.update(kwargs)
1919
+ if "commitQuorum" in kwargs and not supports_quorum:
1920
+ raise ConfigurationError(
1921
+ "Must be connected to MongoDB 4.4+ to use the "
1922
+ "commitQuorum option for createIndexes"
1923
+ )
1924
+
1925
+ self._command(
1926
+ sock_info,
1927
+ cmd,
1928
+ read_preference=ReadPreference.PRIMARY,
1929
+ codec_options=_UNICODE_REPLACE_CODEC_OPTIONS,
1930
+ write_concern=self._write_concern_for(session),
1931
+ session=session,
1932
+ )
1933
+ return names
1934
+
1935
+ def create_index(
1936
+ self,
1937
+ keys: _IndexKeyHint,
1938
+ session: Optional["ClientSession"] = None,
1939
+ comment: Optional[Any] = None,
1940
+ **kwargs: Any,
1941
+ ) -> str:
1942
+ """Creates an index on this collection.
1943
+
1944
+ Takes either a single key or a list of (key, direction) pairs.
1945
+ The key(s) must be an instance of :class:`basestring`
1946
+ (:class:`str` in python 3), and the direction(s) must be one of
1947
+ (:data:`~pymongo.ASCENDING`, :data:`~pymongo.DESCENDING`,
1948
+ :data:`~pymongo.GEO2D`, :data:`~pymongo.GEOSPHERE`,
1949
+ :data:`~pymongo.HASHED`, :data:`~pymongo.TEXT`).
1950
+
1951
+ To create a single key ascending index on the key ``'mike'`` we just
1952
+ use a string argument::
1953
+
1954
+ >>> my_collection.create_index("mike")
1955
+
1956
+ For a compound index on ``'mike'`` descending and ``'eliot'``
1957
+ ascending we need to use a list of tuples::
1958
+
1959
+ >>> my_collection.create_index([("mike", pymongo.DESCENDING),
1960
+ ... ("eliot", pymongo.ASCENDING)])
1961
+
1962
+ All optional index creation parameters should be passed as
1963
+ keyword arguments to this method. For example::
1964
+
1965
+ >>> my_collection.create_index([("mike", pymongo.DESCENDING)],
1966
+ ... background=True)
1967
+
1968
+ Valid options include, but are not limited to:
1969
+
1970
+ - `name`: custom name to use for this index - if none is
1971
+ given, a name will be generated.
1972
+ - `unique`: if ``True``, creates a uniqueness constraint on the
1973
+ index.
1974
+ - `background`: if ``True``, this index should be created in the
1975
+ background.
1976
+ - `sparse`: if ``True``, omit from the index any documents that lack
1977
+ the indexed field.
1978
+ - `bucketSize`: for use with geoHaystack indexes.
1979
+ Number of documents to group together within a certain proximity
1980
+ to a given longitude and latitude.
1981
+ - `min`: minimum value for keys in a :data:`~pymongo.GEO2D`
1982
+ index.
1983
+ - `max`: maximum value for keys in a :data:`~pymongo.GEO2D`
1984
+ index.
1985
+ - `expireAfterSeconds`: <int> Used to create an expiring (TTL)
1986
+ collection. MongoDB will automatically delete documents from
1987
+ this collection after <int> seconds. The indexed field must
1988
+ be a UTC datetime or the data will not expire.
1989
+ - `partialFilterExpression`: A document that specifies a filter for
1990
+ a partial index.
1991
+ - `collation` (optional): An instance of
1992
+ :class:`~pymongo.collation.Collation`.
1993
+ - `wildcardProjection`: Allows users to include or exclude specific
1994
+ field paths from a `wildcard index`_ using the {"$**" : 1} key
1995
+ pattern. Requires MongoDB >= 4.2.
1996
+ - `hidden`: if ``True``, this index will be hidden from the query
1997
+ planner and will not be evaluated as part of query plan
1998
+ selection. Requires MongoDB >= 4.4.
1999
+
2000
+ See the MongoDB documentation for a full list of supported options by
2001
+ server version.
2002
+
2003
+ .. warning:: `dropDups` is not supported by MongoDB 3.0 or newer. The
2004
+ option is silently ignored by the server and unique index builds
2005
+ using the option will fail if a duplicate value is detected.
2006
+
2007
+ .. note:: The :attr:`~pymongo.collection.Collection.write_concern` of
2008
+ this collection is automatically applied to this operation.
2009
+
2010
+ :Parameters:
2011
+ - `keys`: a single key or a list of (key, direction)
2012
+ pairs specifying the index to create
2013
+ - `session` (optional): a
2014
+ :class:`~pymongo.client_session.ClientSession`.
2015
+ arguments
2016
+ - `comment` (optional): A user-provided comment to attach to this
2017
+ command.
2018
+ - `**kwargs` (optional): any additional index creation
2019
+ options (see the above list) should be passed as keyword
2020
+
2021
+ .. versionchanged:: 4.1
2022
+ Added ``comment`` parameter.
2023
+ .. versionchanged:: 3.11
2024
+ Added the ``hidden`` option.
2025
+ .. versionchanged:: 3.6
2026
+ Added ``session`` parameter. Added support for passing maxTimeMS
2027
+ in kwargs.
2028
+ .. versionchanged:: 3.4
2029
+ Apply this collection's write concern automatically to this operation
2030
+ when connected to MongoDB >= 3.4. Support the `collation` option.
2031
+ .. versionchanged:: 3.2
2032
+ Added partialFilterExpression to support partial indexes.
2033
+ .. versionchanged:: 3.0
2034
+ Renamed `key_or_list` to `keys`. Removed the `cache_for` option.
2035
+ :meth:`create_index` no longer caches index names. Removed support
2036
+ for the drop_dups and bucket_size aliases.
2037
+
2038
+ .. seealso:: The MongoDB documentation on `indexes <https://dochub.mongodb.org/core/indexes>`_.
2039
+
2040
+ .. _wildcard index: https://dochub.mongodb.org/core/index-wildcard/
2041
+ """
2042
+ cmd_options = {}
2043
+ if "maxTimeMS" in kwargs:
2044
+ cmd_options["maxTimeMS"] = kwargs.pop("maxTimeMS")
2045
+ if comment is not None:
2046
+ cmd_options["comment"] = comment
2047
+ index = IndexModel(keys, **kwargs)
2048
+ return self.__create_indexes([index], session, **cmd_options)[0]
2049
+
2050
+ def drop_indexes(
2051
+ self,
2052
+ session: Optional["ClientSession"] = None,
2053
+ comment: Optional[Any] = None,
2054
+ **kwargs: Any,
2055
+ ) -> None:
2056
+ """Drops all indexes on this collection.
2057
+
2058
+ Can be used on non-existant collections or collections with no indexes.
2059
+ Raises OperationFailure on an error.
2060
+
2061
+ :Parameters:
2062
+ - `session` (optional): a
2063
+ :class:`~pymongo.client_session.ClientSession`.
2064
+ arguments
2065
+ - `comment` (optional): A user-provided comment to attach to this
2066
+ command.
2067
+ - `**kwargs` (optional): optional arguments to the createIndexes
2068
+ command (like maxTimeMS) can be passed as keyword arguments.
2069
+
2070
+
2071
+
2072
+ .. note:: The :attr:`~pymongo.collection.Collection.write_concern` of
2073
+ this collection is automatically applied to this operation.
2074
+
2075
+ .. versionchanged:: 3.6
2076
+ Added ``session`` parameter. Added support for arbitrary keyword
2077
+ arguments.
2078
+
2079
+ .. versionchanged:: 3.4
2080
+ Apply this collection's write concern automatically to this operation
2081
+ when connected to MongoDB >= 3.4.
2082
+
2083
+ """
2084
+ if comment is not None:
2085
+ kwargs["comment"] = comment
2086
+ self.drop_index("*", session=session, **kwargs)
2087
+
2088
+ @_csot.apply
2089
+ def drop_index(
2090
+ self,
2091
+ index_or_name: _IndexKeyHint,
2092
+ session: Optional["ClientSession"] = None,
2093
+ comment: Optional[Any] = None,
2094
+ **kwargs: Any,
2095
+ ) -> None:
2096
+ """Drops the specified index on this collection.
2097
+
2098
+ Can be used on non-existant collections or collections with no
2099
+ indexes. Raises OperationFailure on an error (e.g. trying to
2100
+ drop an index that does not exist). `index_or_name`
2101
+ can be either an index name (as returned by `create_index`),
2102
+ or an index specifier (as passed to `create_index`). An index
2103
+ specifier should be a list of (key, direction) pairs. Raises
2104
+ TypeError if index is not an instance of (str, unicode, list).
2105
+
2106
+ .. warning::
2107
+
2108
+ if a custom name was used on index creation (by
2109
+ passing the `name` parameter to :meth:`create_index`) the index
2110
+ **must** be dropped by name.
2111
+
2112
+ :Parameters:
2113
+ - `index_or_name`: index (or name of index) to drop
2114
+ - `session` (optional): a
2115
+ :class:`~pymongo.client_session.ClientSession`.
2116
+ - `comment` (optional): A user-provided comment to attach to this
2117
+ command.
2118
+ - `**kwargs` (optional): optional arguments to the createIndexes
2119
+ command (like maxTimeMS) can be passed as keyword arguments.
2120
+
2121
+
2122
+
2123
+ .. note:: The :attr:`~pymongo.collection.Collection.write_concern` of
2124
+ this collection is automatically applied to this operation.
2125
+
2126
+
2127
+ .. versionchanged:: 3.6
2128
+ Added ``session`` parameter. Added support for arbitrary keyword
2129
+ arguments.
2130
+
2131
+ .. versionchanged:: 3.4
2132
+ Apply this collection's write concern automatically to this operation
2133
+ when connected to MongoDB >= 3.4.
2134
+
2135
+ """
2136
+ name = index_or_name
2137
+ if isinstance(index_or_name, list):
2138
+ name = helpers._gen_index_name(index_or_name)
2139
+
2140
+ if not isinstance(name, str):
2141
+ raise TypeError("index_or_name must be an instance of str or list")
2142
+
2143
+ cmd = SON([("dropIndexes", self.__name), ("index", name)])
2144
+ cmd.update(kwargs)
2145
+ if comment is not None:
2146
+ cmd["comment"] = comment
2147
+ with self._socket_for_writes(session) as sock_info:
2148
+ self._command(
2149
+ sock_info,
2150
+ cmd,
2151
+ read_preference=ReadPreference.PRIMARY,
2152
+ allowable_errors=["ns not found", 26],
2153
+ write_concern=self._write_concern_for(session),
2154
+ session=session,
2155
+ )
2156
+
2157
+ def list_indexes(
2158
+ self,
2159
+ session: Optional["ClientSession"] = None,
2160
+ comment: Optional[Any] = None,
2161
+ ) -> CommandCursor[MutableMapping[str, Any]]:
2162
+ """Get a cursor over the index documents for this collection.
2163
+
2164
+ >>> for index in db.test.list_indexes():
2165
+ ... print(index)
2166
+ ...
2167
+ SON([('v', 2), ('key', SON([('_id', 1)])), ('name', '_id_')])
2168
+
2169
+ :Parameters:
2170
+ - `session` (optional): a
2171
+ :class:`~pymongo.client_session.ClientSession`.
2172
+ - `comment` (optional): A user-provided comment to attach to this
2173
+ command.
2174
+
2175
+ :Returns:
2176
+ An instance of :class:`~pymongo.command_cursor.CommandCursor`.
2177
+
2178
+ .. versionchanged:: 4.1
2179
+ Added ``comment`` parameter.
2180
+
2181
+ .. versionchanged:: 3.6
2182
+ Added ``session`` parameter.
2183
+
2184
+ .. versionadded:: 3.0
2185
+ """
2186
+ codec_options: CodecOptions = CodecOptions(SON)
2187
+ coll = self.with_options(
2188
+ codec_options=codec_options, read_preference=ReadPreference.PRIMARY
2189
+ )
2190
+ read_pref = (session and session._txn_read_preference()) or ReadPreference.PRIMARY
2191
+ explicit_session = session is not None
2192
+
2193
+ def _cmd(session, server, sock_info, read_preference):
2194
+ cmd = SON([("listIndexes", self.__name), ("cursor", {})])
2195
+ if comment is not None:
2196
+ cmd["comment"] = comment
2197
+
2198
+ try:
2199
+ cursor = self._command(
2200
+ sock_info, cmd, read_preference, codec_options, session=session
2201
+ )["cursor"]
2202
+ except OperationFailure as exc:
2203
+ # Ignore NamespaceNotFound errors to match the behavior
2204
+ # of reading from *.system.indexes.
2205
+ if exc.code != 26:
2206
+ raise
2207
+ cursor = {"id": 0, "firstBatch": []}
2208
+ cmd_cursor = CommandCursor(
2209
+ coll,
2210
+ cursor,
2211
+ sock_info.address,
2212
+ session=session,
2213
+ explicit_session=explicit_session,
2214
+ comment=cmd.get("comment"),
2215
+ )
2216
+ cmd_cursor._maybe_pin_connection(sock_info)
2217
+ return cmd_cursor
2218
+
2219
+ with self.__database.client._tmp_session(session, False) as s:
2220
+ return self.__database.client._retryable_read(_cmd, read_pref, s)
2221
+
2222
+ def index_information(
2223
+ self,
2224
+ session: Optional["ClientSession"] = None,
2225
+ comment: Optional[Any] = None,
2226
+ ) -> MutableMapping[str, Any]:
2227
+ """Get information on this collection's indexes.
2228
+
2229
+ Returns a dictionary where the keys are index names (as
2230
+ returned by create_index()) and the values are dictionaries
2231
+ containing information about each index. The dictionary is
2232
+ guaranteed to contain at least a single key, ``"key"`` which
2233
+ is a list of (key, direction) pairs specifying the index (as
2234
+ passed to create_index()). It will also contain any other
2235
+ metadata about the indexes, except for the ``"ns"`` and
2236
+ ``"name"`` keys, which are cleaned. Example output might look
2237
+ like this:
2238
+
2239
+ >>> db.test.create_index("x", unique=True)
2240
+ 'x_1'
2241
+ >>> db.test.index_information()
2242
+ {'_id_': {'key': [('_id', 1)]},
2243
+ 'x_1': {'unique': True, 'key': [('x', 1)]}}
2244
+
2245
+ :Parameters:
2246
+ - `session` (optional): a
2247
+ :class:`~pymongo.client_session.ClientSession`.
2248
+ - `comment` (optional): A user-provided comment to attach to this
2249
+ command.
2250
+
2251
+ .. versionchanged:: 4.1
2252
+ Added ``comment`` parameter.
2253
+
2254
+ .. versionchanged:: 3.6
2255
+ Added ``session`` parameter.
2256
+ """
2257
+ cursor = self.list_indexes(session=session, comment=comment)
2258
+ info = {}
2259
+ for index in cursor:
2260
+ index["key"] = list(index["key"].items())
2261
+ index = dict(index)
2262
+ info[index.pop("name")] = index
2263
+ return info
2264
+
2265
+ def options(
2266
+ self,
2267
+ session: Optional["ClientSession"] = None,
2268
+ comment: Optional[Any] = None,
2269
+ ) -> MutableMapping[str, Any]:
2270
+ """Get the options set on this collection.
2271
+
2272
+ Returns a dictionary of options and their values - see
2273
+ :meth:`~pymongo.database.Database.create_collection` for more
2274
+ information on the possible options. Returns an empty
2275
+ dictionary if the collection has not been created yet.
2276
+
2277
+ :Parameters:
2278
+ - `session` (optional): a
2279
+ :class:`~pymongo.client_session.ClientSession`.
2280
+ - `comment` (optional): A user-provided comment to attach to this
2281
+ command.
2282
+
2283
+ .. versionchanged:: 3.6
2284
+ Added ``session`` parameter.
2285
+ """
2286
+ dbo = self.__database.client.get_database(
2287
+ self.__database.name,
2288
+ self.codec_options,
2289
+ self.read_preference,
2290
+ self.write_concern,
2291
+ self.read_concern,
2292
+ )
2293
+ cursor = dbo.list_collections(
2294
+ session=session, filter={"name": self.__name}, comment=comment
2295
+ )
2296
+
2297
+ result = None
2298
+ for doc in cursor:
2299
+ result = doc
2300
+ break
2301
+
2302
+ if not result:
2303
+ return {}
2304
+
2305
+ options = result.get("options", {})
2306
+ assert options is not None
2307
+ if "create" in options:
2308
+ del options["create"]
2309
+
2310
+ return options
2311
+
2312
+ @_csot.apply
2313
+ def _aggregate(
2314
+ self,
2315
+ aggregation_command,
2316
+ pipeline,
2317
+ cursor_class,
2318
+ session,
2319
+ explicit_session,
2320
+ let=None,
2321
+ comment=None,
2322
+ **kwargs,
2323
+ ):
2324
+ if comment is not None:
2325
+ kwargs["comment"] = comment
2326
+ cmd = aggregation_command(
2327
+ self,
2328
+ cursor_class,
2329
+ pipeline,
2330
+ kwargs,
2331
+ explicit_session,
2332
+ let,
2333
+ user_fields={"cursor": {"firstBatch": 1}},
2334
+ )
2335
+
2336
+ return self.__database.client._retryable_read(
2337
+ cmd.get_cursor,
2338
+ cmd.get_read_preference(session),
2339
+ session,
2340
+ retryable=not cmd._performs_write,
2341
+ )
2342
+
2343
+ def aggregate(
2344
+ self,
2345
+ pipeline: _Pipeline,
2346
+ session: Optional["ClientSession"] = None,
2347
+ let: Optional[Mapping[str, Any]] = None,
2348
+ comment: Optional[Any] = None,
2349
+ **kwargs: Any,
2350
+ ) -> CommandCursor[_DocumentType]:
2351
+ """Perform an aggregation using the aggregation framework on this
2352
+ collection.
2353
+
2354
+ The :meth:`aggregate` method obeys the :attr:`read_preference` of this
2355
+ :class:`Collection`, except when ``$out`` or ``$merge`` are used on
2356
+ MongoDB <5.0, in which case
2357
+ :attr:`~pymongo.read_preferences.ReadPreference.PRIMARY` is used.
2358
+
2359
+ .. note:: This method does not support the 'explain' option. Please
2360
+ use :meth:`~pymongo.database.Database.command` instead. An
2361
+ example is included in the :ref:`aggregate-examples` documentation.
2362
+
2363
+ .. note:: The :attr:`~pymongo.collection.Collection.write_concern` of
2364
+ this collection is automatically applied to this operation.
2365
+
2366
+ :Parameters:
2367
+ - `pipeline`: a list of aggregation pipeline stages
2368
+ - `session` (optional): a
2369
+ :class:`~pymongo.client_session.ClientSession`.
2370
+ - `**kwargs` (optional): extra `aggregate command`_ parameters.
2371
+
2372
+ All optional `aggregate command`_ parameters should be passed as
2373
+ keyword arguments to this method. Valid options include, but are not
2374
+ limited to:
2375
+
2376
+ - `allowDiskUse` (bool): Enables writing to temporary files. When set
2377
+ to True, aggregation stages can write data to the _tmp subdirectory
2378
+ of the --dbpath directory. The default is False.
2379
+ - `maxTimeMS` (int): The maximum amount of time to allow the operation
2380
+ to run in milliseconds.
2381
+ - `batchSize` (int): The maximum number of documents to return per
2382
+ batch. Ignored if the connected mongod or mongos does not support
2383
+ returning aggregate results using a cursor.
2384
+ - `collation` (optional): An instance of
2385
+ :class:`~pymongo.collation.Collation`.
2386
+ - `let` (dict): A dict of parameter names and values. Values must be
2387
+ constant or closed expressions that do not reference document
2388
+ fields. Parameters can then be accessed as variables in an
2389
+ aggregate expression context (e.g. ``"$$var"``). This option is
2390
+ only supported on MongoDB >= 5.0.
2391
+ - `comment` (optional): A user-provided comment to attach to this
2392
+ command.
2393
+
2394
+
2395
+ :Returns:
2396
+ A :class:`~pymongo.command_cursor.CommandCursor` over the result
2397
+ set.
2398
+
2399
+ .. versionchanged:: 4.1
2400
+ Added ``comment`` parameter.
2401
+ Added ``let`` parameter.
2402
+ Support $merge and $out executing on secondaries according to the
2403
+ collection's :attr:`read_preference`.
2404
+ .. versionchanged:: 4.0
2405
+ Removed the ``useCursor`` option.
2406
+ .. versionchanged:: 3.9
2407
+ Apply this collection's read concern to pipelines containing the
2408
+ `$out` stage when connected to MongoDB >= 4.2.
2409
+ Added support for the ``$merge`` pipeline stage.
2410
+ Aggregations that write always use read preference
2411
+ :attr:`~pymongo.read_preferences.ReadPreference.PRIMARY`.
2412
+ .. versionchanged:: 3.6
2413
+ Added the `session` parameter. Added the `maxAwaitTimeMS` option.
2414
+ Deprecated the `useCursor` option.
2415
+ .. versionchanged:: 3.4
2416
+ Apply this collection's write concern automatically to this operation
2417
+ when connected to MongoDB >= 3.4. Support the `collation` option.
2418
+ .. versionchanged:: 3.0
2419
+ The :meth:`aggregate` method always returns a CommandCursor. The
2420
+ pipeline argument must be a list.
2421
+
2422
+ .. seealso:: :doc:`/examples/aggregation`
2423
+
2424
+ .. _aggregate command:
2425
+ https://mongodb.com/docs/manual/reference/command/aggregate
2426
+ """
2427
+
2428
+ with self.__database.client._tmp_session(session, close=False) as s:
2429
+ return self._aggregate(
2430
+ _CollectionAggregationCommand,
2431
+ pipeline,
2432
+ CommandCursor,
2433
+ session=s,
2434
+ explicit_session=session is not None,
2435
+ let=let,
2436
+ comment=comment,
2437
+ **kwargs,
2438
+ )
2439
+
2440
+ def aggregate_raw_batches(
2441
+ self,
2442
+ pipeline: _Pipeline,
2443
+ session: Optional["ClientSession"] = None,
2444
+ comment: Optional[Any] = None,
2445
+ **kwargs: Any,
2446
+ ) -> RawBatchCursor[_DocumentType]:
2447
+ """Perform an aggregation and retrieve batches of raw BSON.
2448
+
2449
+ Similar to the :meth:`aggregate` method but returns a
2450
+ :class:`~pymongo.cursor.RawBatchCursor`.
2451
+
2452
+ This example demonstrates how to work with raw batches, but in practice
2453
+ raw batches should be passed to an external library that can decode
2454
+ BSON into another data type, rather than used with PyMongo's
2455
+ :mod:`bson` module.
2456
+
2457
+ >>> import bson
2458
+ >>> cursor = db.test.aggregate_raw_batches([
2459
+ ... {'$project': {'x': {'$multiply': [2, '$x']}}}])
2460
+ >>> for batch in cursor:
2461
+ ... print(bson.decode_all(batch))
2462
+
2463
+ .. note:: aggregate_raw_batches does not support auto encryption.
2464
+
2465
+ .. versionchanged:: 3.12
2466
+ Added session support.
2467
+
2468
+ .. versionadded:: 3.6
2469
+ """
2470
+ # OP_MSG is required to support encryption.
2471
+ if self.__database.client._encrypter:
2472
+ raise InvalidOperation("aggregate_raw_batches does not support auto encryption")
2473
+ if comment is not None:
2474
+ kwargs["comment"] = comment
2475
+ with self.__database.client._tmp_session(session, close=False) as s:
2476
+ return self._aggregate(
2477
+ _CollectionRawAggregationCommand,
2478
+ pipeline,
2479
+ RawBatchCommandCursor,
2480
+ session=s,
2481
+ explicit_session=session is not None,
2482
+ **kwargs,
2483
+ )
2484
+
2485
+ def watch(
2486
+ self,
2487
+ pipeline: Optional[_Pipeline] = None,
2488
+ full_document: Optional[str] = None,
2489
+ resume_after: Optional[Mapping[str, Any]] = None,
2490
+ max_await_time_ms: Optional[int] = None,
2491
+ batch_size: Optional[int] = None,
2492
+ collation: Optional[_CollationIn] = None,
2493
+ start_at_operation_time: Optional[Timestamp] = None,
2494
+ session: Optional["ClientSession"] = None,
2495
+ start_after: Optional[Mapping[str, Any]] = None,
2496
+ comment: Optional[Any] = None,
2497
+ full_document_before_change: Optional[str] = None,
2498
+ ) -> CollectionChangeStream[_DocumentType]:
2499
+ """Watch changes on this collection.
2500
+
2501
+ Performs an aggregation with an implicit initial ``$changeStream``
2502
+ stage and returns a
2503
+ :class:`~pymongo.change_stream.CollectionChangeStream` cursor which
2504
+ iterates over changes on this collection.
2505
+
2506
+ .. code-block:: python
2507
+
2508
+ with db.collection.watch() as stream:
2509
+ for change in stream:
2510
+ print(change)
2511
+
2512
+ The :class:`~pymongo.change_stream.CollectionChangeStream` iterable
2513
+ blocks until the next change document is returned or an error is
2514
+ raised. If the
2515
+ :meth:`~pymongo.change_stream.CollectionChangeStream.next` method
2516
+ encounters a network error when retrieving a batch from the server,
2517
+ it will automatically attempt to recreate the cursor such that no
2518
+ change events are missed. Any error encountered during the resume
2519
+ attempt indicates there may be an outage and will be raised.
2520
+
2521
+ .. code-block:: python
2522
+
2523
+ try:
2524
+ with db.collection.watch(
2525
+ [{'$match': {'operationType': 'insert'}}]) as stream:
2526
+ for insert_change in stream:
2527
+ print(insert_change)
2528
+ except pymongo.errors.PyMongoError:
2529
+ # The ChangeStream encountered an unrecoverable error or the
2530
+ # resume attempt failed to recreate the cursor.
2531
+ logging.error('...')
2532
+
2533
+ For a precise description of the resume process see the
2534
+ `change streams specification`_.
2535
+
2536
+ .. note:: Using this helper method is preferred to directly calling
2537
+ :meth:`~pymongo.collection.Collection.aggregate` with a
2538
+ ``$changeStream`` stage, for the purpose of supporting
2539
+ resumability.
2540
+
2541
+ .. warning:: This Collection's :attr:`read_concern` must be
2542
+ ``ReadConcern("majority")`` in order to use the ``$changeStream``
2543
+ stage.
2544
+
2545
+ :Parameters:
2546
+ - `pipeline` (optional): A list of aggregation pipeline stages to
2547
+ append to an initial ``$changeStream`` stage. Not all
2548
+ pipeline stages are valid after a ``$changeStream`` stage, see the
2549
+ MongoDB documentation on change streams for the supported stages.
2550
+ - `full_document` (optional): The fullDocument to pass as an option
2551
+ to the ``$changeStream`` stage. Allowed values: 'updateLookup',
2552
+ 'whenAvailable', 'required'. When set to 'updateLookup', the
2553
+ change notification for partial updates will include both a delta
2554
+ describing the changes to the document, as well as a copy of the
2555
+ entire document that was changed from some time after the change
2556
+ occurred.
2557
+ - `full_document_before_change`: Allowed values: 'whenAvailable'
2558
+ and 'required'. Change events may now result in a
2559
+ 'fullDocumentBeforeChange' response field.
2560
+ - `resume_after` (optional): A resume token. If provided, the
2561
+ change stream will start returning changes that occur directly
2562
+ after the operation specified in the resume token. A resume token
2563
+ is the _id value of a change document.
2564
+ - `max_await_time_ms` (optional): The maximum time in milliseconds
2565
+ for the server to wait for changes before responding to a getMore
2566
+ operation.
2567
+ - `batch_size` (optional): The maximum number of documents to return
2568
+ per batch.
2569
+ - `collation` (optional): The :class:`~pymongo.collation.Collation`
2570
+ to use for the aggregation.
2571
+ - `start_at_operation_time` (optional): If provided, the resulting
2572
+ change stream will only return changes that occurred at or after
2573
+ the specified :class:`~bson.timestamp.Timestamp`. Requires
2574
+ MongoDB >= 4.0.
2575
+ - `session` (optional): a
2576
+ :class:`~pymongo.client_session.ClientSession`.
2577
+ - `start_after` (optional): The same as `resume_after` except that
2578
+ `start_after` can resume notifications after an invalidate event.
2579
+ This option and `resume_after` are mutually exclusive.
2580
+ - `comment` (optional): A user-provided comment to attach to this
2581
+ command.
2582
+
2583
+ :Returns:
2584
+ A :class:`~pymongo.change_stream.CollectionChangeStream` cursor.
2585
+
2586
+ .. versionchanged:: 4.2
2587
+ Added ``full_document_before_change`` parameter.
2588
+
2589
+ .. versionchanged:: 4.1
2590
+ Added ``comment`` parameter.
2591
+
2592
+ .. versionchanged:: 3.9
2593
+ Added the ``start_after`` parameter.
2594
+
2595
+ .. versionchanged:: 3.7
2596
+ Added the ``start_at_operation_time`` parameter.
2597
+
2598
+ .. versionadded:: 3.6
2599
+
2600
+ .. seealso:: The MongoDB documentation on `changeStreams <https://mongodb.com/docs/manual/changeStreams/>`_.
2601
+
2602
+ .. _change streams specification:
2603
+ https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst
2604
+ """
2605
+ return CollectionChangeStream(
2606
+ self,
2607
+ pipeline,
2608
+ full_document,
2609
+ resume_after,
2610
+ max_await_time_ms,
2611
+ batch_size,
2612
+ collation,
2613
+ start_at_operation_time,
2614
+ session,
2615
+ start_after,
2616
+ comment,
2617
+ full_document_before_change,
2618
+ )
2619
+
2620
+ @_csot.apply
2621
+ def rename(
2622
+ self,
2623
+ new_name: str,
2624
+ session: Optional["ClientSession"] = None,
2625
+ comment: Optional[Any] = None,
2626
+ **kwargs: Any,
2627
+ ) -> MutableMapping[str, Any]:
2628
+ """Rename this collection.
2629
+
2630
+ If operating in auth mode, client must be authorized as an
2631
+ admin to perform this operation. Raises :class:`TypeError` if
2632
+ `new_name` is not an instance of :class:`basestring`
2633
+ (:class:`str` in python 3). Raises :class:`~pymongo.errors.InvalidName`
2634
+ if `new_name` is not a valid collection name.
2635
+
2636
+ :Parameters:
2637
+ - `new_name`: new name for this collection
2638
+ - `session` (optional): a
2639
+ :class:`~pymongo.client_session.ClientSession`.
2640
+ - `comment` (optional): A user-provided comment to attach to this
2641
+ command.
2642
+ - `**kwargs` (optional): additional arguments to the rename command
2643
+ may be passed as keyword arguments to this helper method
2644
+ (i.e. ``dropTarget=True``)
2645
+
2646
+ .. note:: The :attr:`~pymongo.collection.Collection.write_concern` of
2647
+ this collection is automatically applied to this operation.
2648
+
2649
+ .. versionchanged:: 3.6
2650
+ Added ``session`` parameter.
2651
+
2652
+ .. versionchanged:: 3.4
2653
+ Apply this collection's write concern automatically to this operation
2654
+ when connected to MongoDB >= 3.4.
2655
+
2656
+ """
2657
+ if not isinstance(new_name, str):
2658
+ raise TypeError("new_name must be an instance of str")
2659
+
2660
+ if not new_name or ".." in new_name:
2661
+ raise InvalidName("collection names cannot be empty")
2662
+ if new_name[0] == "." or new_name[-1] == ".":
2663
+ raise InvalidName("collecion names must not start or end with '.'")
2664
+ if "$" in new_name and not new_name.startswith("oplog.$main"):
2665
+ raise InvalidName("collection names must not contain '$'")
2666
+
2667
+ new_name = "%s.%s" % (self.__database.name, new_name)
2668
+ cmd = SON([("renameCollection", self.__full_name), ("to", new_name)])
2669
+ cmd.update(kwargs)
2670
+ if comment is not None:
2671
+ cmd["comment"] = comment
2672
+ write_concern = self._write_concern_for_cmd(cmd, session)
2673
+
2674
+ with self._socket_for_writes(session) as sock_info:
2675
+ with self.__database.client._tmp_session(session) as s:
2676
+ return sock_info.command(
2677
+ "admin",
2678
+ cmd,
2679
+ write_concern=write_concern,
2680
+ parse_write_concern_error=True,
2681
+ session=s,
2682
+ client=self.__database.client,
2683
+ )
2684
+
2685
+ def distinct(
2686
+ self,
2687
+ key: str,
2688
+ filter: Optional[Mapping[str, Any]] = None,
2689
+ session: Optional["ClientSession"] = None,
2690
+ comment: Optional[Any] = None,
2691
+ **kwargs: Any,
2692
+ ) -> List:
2693
+ """Get a list of distinct values for `key` among all documents
2694
+ in this collection.
2695
+
2696
+ Raises :class:`TypeError` if `key` is not an instance of
2697
+ :class:`basestring` (:class:`str` in python 3).
2698
+
2699
+ All optional distinct parameters should be passed as keyword arguments
2700
+ to this method. Valid options include:
2701
+
2702
+ - `maxTimeMS` (int): The maximum amount of time to allow the count
2703
+ command to run, in milliseconds.
2704
+ - `collation` (optional): An instance of
2705
+ :class:`~pymongo.collation.Collation`.
2706
+
2707
+ The :meth:`distinct` method obeys the :attr:`read_preference` of
2708
+ this :class:`Collection`.
2709
+
2710
+ :Parameters:
2711
+ - `key`: name of the field for which we want to get the distinct
2712
+ values
2713
+ - `filter` (optional): A query document that specifies the documents
2714
+ from which to retrieve the distinct values.
2715
+ - `session` (optional): a
2716
+ :class:`~pymongo.client_session.ClientSession`.
2717
+ - `comment` (optional): A user-provided comment to attach to this
2718
+ command.
2719
+ - `**kwargs` (optional): See list of options above.
2720
+
2721
+ .. versionchanged:: 3.6
2722
+ Added ``session`` parameter.
2723
+
2724
+ .. versionchanged:: 3.4
2725
+ Support the `collation` option.
2726
+
2727
+ """
2728
+ if not isinstance(key, str):
2729
+ raise TypeError("key must be an instance of str")
2730
+ cmd = SON([("distinct", self.__name), ("key", key)])
2731
+ if filter is not None:
2732
+ if "query" in kwargs:
2733
+ raise ConfigurationError("can't pass both filter and query")
2734
+ kwargs["query"] = filter
2735
+ collation = validate_collation_or_none(kwargs.pop("collation", None))
2736
+ cmd.update(kwargs)
2737
+ if comment is not None:
2738
+ cmd["comment"] = comment
2739
+
2740
+ def _cmd(session, server, sock_info, read_preference):
2741
+ return self._command(
2742
+ sock_info,
2743
+ cmd,
2744
+ read_preference=read_preference,
2745
+ read_concern=self.read_concern,
2746
+ collation=collation,
2747
+ session=session,
2748
+ user_fields={"values": 1},
2749
+ )["values"]
2750
+
2751
+ return self._retryable_non_cursor_read(_cmd, session)
2752
+
2753
+ def _write_concern_for_cmd(self, cmd, session):
2754
+ raw_wc = cmd.get("writeConcern")
2755
+ if raw_wc is not None:
2756
+ return WriteConcern(**raw_wc)
2757
+ else:
2758
+ return self._write_concern_for(session)
2759
+
2760
+ def __find_and_modify(
2761
+ self,
2762
+ filter,
2763
+ projection,
2764
+ sort,
2765
+ upsert=None,
2766
+ return_document=ReturnDocument.BEFORE,
2767
+ array_filters=None,
2768
+ hint=None,
2769
+ session=None,
2770
+ let=None,
2771
+ **kwargs,
2772
+ ):
2773
+ """Internal findAndModify helper."""
2774
+
2775
+ common.validate_is_mapping("filter", filter)
2776
+ if not isinstance(return_document, bool):
2777
+ raise ValueError(
2778
+ "return_document must be ReturnDocument.BEFORE or ReturnDocument.AFTER"
2779
+ )
2780
+ collation = validate_collation_or_none(kwargs.pop("collation", None))
2781
+ cmd = SON([("findAndModify", self.__name), ("query", filter), ("new", return_document)])
2782
+ if let is not None:
2783
+ common.validate_is_mapping("let", let)
2784
+ cmd["let"] = let
2785
+ cmd.update(kwargs)
2786
+ if projection is not None:
2787
+ cmd["fields"] = helpers._fields_list_to_dict(projection, "projection")
2788
+ if sort is not None:
2789
+ cmd["sort"] = helpers._index_document(sort)
2790
+ if upsert is not None:
2791
+ common.validate_boolean("upsert", upsert)
2792
+ cmd["upsert"] = upsert
2793
+ if hint is not None:
2794
+ if not isinstance(hint, str):
2795
+ hint = helpers._index_document(hint)
2796
+
2797
+ write_concern = self._write_concern_for_cmd(cmd, session)
2798
+
2799
+ def _find_and_modify(session, sock_info, retryable_write):
2800
+ acknowledged = write_concern.acknowledged
2801
+ if array_filters is not None:
2802
+ if not acknowledged:
2803
+ raise ConfigurationError(
2804
+ "arrayFilters is unsupported for unacknowledged writes."
2805
+ )
2806
+ cmd["arrayFilters"] = list(array_filters)
2807
+ if hint is not None:
2808
+ if sock_info.max_wire_version < 8:
2809
+ raise ConfigurationError(
2810
+ "Must be connected to MongoDB 4.2+ to use hint on find and modify commands."
2811
+ )
2812
+ elif not acknowledged and sock_info.max_wire_version < 9:
2813
+ raise ConfigurationError(
2814
+ "Must be connected to MongoDB 4.4+ to use hint on unacknowledged find and modify commands."
2815
+ )
2816
+ cmd["hint"] = hint
2817
+ out = self._command(
2818
+ sock_info,
2819
+ cmd,
2820
+ read_preference=ReadPreference.PRIMARY,
2821
+ write_concern=write_concern,
2822
+ collation=collation,
2823
+ session=session,
2824
+ retryable_write=retryable_write,
2825
+ user_fields=_FIND_AND_MODIFY_DOC_FIELDS,
2826
+ )
2827
+ _check_write_command_response(out)
2828
+
2829
+ return out.get("value")
2830
+
2831
+ return self.__database.client._retryable_write(
2832
+ write_concern.acknowledged, _find_and_modify, session
2833
+ )
2834
+
2835
+ def find_one_and_delete(
2836
+ self,
2837
+ filter: Mapping[str, Any],
2838
+ projection: Optional[Union[Mapping[str, Any], Iterable[str]]] = None,
2839
+ sort: Optional[_IndexList] = None,
2840
+ hint: Optional[_IndexKeyHint] = None,
2841
+ session: Optional["ClientSession"] = None,
2842
+ let: Optional[Mapping[str, Any]] = None,
2843
+ comment: Optional[Any] = None,
2844
+ **kwargs: Any,
2845
+ ) -> _DocumentType:
2846
+ """Finds a single document and deletes it, returning the document.
2847
+
2848
+ >>> db.test.count_documents({'x': 1})
2849
+ 2
2850
+ >>> db.test.find_one_and_delete({'x': 1})
2851
+ {'x': 1, '_id': ObjectId('54f4e12bfba5220aa4d6dee8')}
2852
+ >>> db.test.count_documents({'x': 1})
2853
+ 1
2854
+
2855
+ If multiple documents match *filter*, a *sort* can be applied.
2856
+
2857
+ >>> for doc in db.test.find({'x': 1}):
2858
+ ... print(doc)
2859
+ ...
2860
+ {'x': 1, '_id': 0}
2861
+ {'x': 1, '_id': 1}
2862
+ {'x': 1, '_id': 2}
2863
+ >>> db.test.find_one_and_delete(
2864
+ ... {'x': 1}, sort=[('_id', pymongo.DESCENDING)])
2865
+ {'x': 1, '_id': 2}
2866
+
2867
+ The *projection* option can be used to limit the fields returned.
2868
+
2869
+ >>> db.test.find_one_and_delete({'x': 1}, projection={'_id': False})
2870
+ {'x': 1}
2871
+
2872
+ :Parameters:
2873
+ - `filter`: A query that matches the document to delete.
2874
+ - `projection` (optional): a list of field names that should be
2875
+ returned in the result document or a mapping specifying the fields
2876
+ to include or exclude. If `projection` is a list "_id" will
2877
+ always be returned. Use a mapping to exclude fields from
2878
+ the result (e.g. projection={'_id': False}).
2879
+ - `sort` (optional): a list of (key, direction) pairs
2880
+ specifying the sort order for the query. If multiple documents
2881
+ match the query, they are sorted and the first is deleted.
2882
+ - `hint` (optional): An index to use to support the query predicate
2883
+ specified either by its string name, or in the same format as
2884
+ passed to :meth:`~pymongo.collection.Collection.create_index`
2885
+ (e.g. ``[('field', ASCENDING)]``). This option is only supported
2886
+ on MongoDB 4.4 and above.
2887
+ - `session` (optional): a
2888
+ :class:`~pymongo.client_session.ClientSession`.
2889
+ - `let` (optional): Map of parameter names and values. Values must be
2890
+ constant or closed expressions that do not reference document
2891
+ fields. Parameters can then be accessed as variables in an
2892
+ aggregate expression context (e.g. "$$var").
2893
+ - `comment` (optional): A user-provided comment to attach to this
2894
+ command.
2895
+ - `**kwargs` (optional): additional command arguments can be passed
2896
+ as keyword arguments (for example maxTimeMS can be used with
2897
+ recent server versions).
2898
+
2899
+ .. versionchanged:: 4.1
2900
+ Added ``let`` parameter.
2901
+ .. versionchanged:: 3.11
2902
+ Added ``hint`` parameter.
2903
+ .. versionchanged:: 3.6
2904
+ Added ``session`` parameter.
2905
+ .. versionchanged:: 3.2
2906
+ Respects write concern.
2907
+
2908
+ .. warning:: Starting in PyMongo 3.2, this command uses the
2909
+ :class:`~pymongo.write_concern.WriteConcern` of this
2910
+ :class:`~pymongo.collection.Collection` when connected to MongoDB >=
2911
+ 3.2. Note that using an elevated write concern with this command may
2912
+ be slower compared to using the default write concern.
2913
+
2914
+ .. versionchanged:: 3.4
2915
+ Added the `collation` option.
2916
+ .. versionadded:: 3.0
2917
+ """
2918
+ kwargs["remove"] = True
2919
+ if comment is not None:
2920
+ kwargs["comment"] = comment
2921
+ return self.__find_and_modify(
2922
+ filter, projection, sort, let=let, hint=hint, session=session, **kwargs
2923
+ )
2924
+
2925
+ def find_one_and_replace(
2926
+ self,
2927
+ filter: Mapping[str, Any],
2928
+ replacement: Mapping[str, Any],
2929
+ projection: Optional[Union[Mapping[str, Any], Iterable[str]]] = None,
2930
+ sort: Optional[_IndexList] = None,
2931
+ upsert: bool = False,
2932
+ return_document: bool = ReturnDocument.BEFORE,
2933
+ hint: Optional[_IndexKeyHint] = None,
2934
+ session: Optional["ClientSession"] = None,
2935
+ let: Optional[Mapping[str, Any]] = None,
2936
+ comment: Optional[Any] = None,
2937
+ **kwargs: Any,
2938
+ ) -> _DocumentType:
2939
+ """Finds a single document and replaces it, returning either the
2940
+ original or the replaced document.
2941
+
2942
+ The :meth:`find_one_and_replace` method differs from
2943
+ :meth:`find_one_and_update` by replacing the document matched by
2944
+ *filter*, rather than modifying the existing document.
2945
+
2946
+ >>> for doc in db.test.find({}):
2947
+ ... print(doc)
2948
+ ...
2949
+ {'x': 1, '_id': 0}
2950
+ {'x': 1, '_id': 1}
2951
+ {'x': 1, '_id': 2}
2952
+ >>> db.test.find_one_and_replace({'x': 1}, {'y': 1})
2953
+ {'x': 1, '_id': 0}
2954
+ >>> for doc in db.test.find({}):
2955
+ ... print(doc)
2956
+ ...
2957
+ {'y': 1, '_id': 0}
2958
+ {'x': 1, '_id': 1}
2959
+ {'x': 1, '_id': 2}
2960
+
2961
+ :Parameters:
2962
+ - `filter`: A query that matches the document to replace.
2963
+ - `replacement`: The replacement document.
2964
+ - `projection` (optional): A list of field names that should be
2965
+ returned in the result document or a mapping specifying the fields
2966
+ to include or exclude. If `projection` is a list "_id" will
2967
+ always be returned. Use a mapping to exclude fields from
2968
+ the result (e.g. projection={'_id': False}).
2969
+ - `sort` (optional): a list of (key, direction) pairs
2970
+ specifying the sort order for the query. If multiple documents
2971
+ match the query, they are sorted and the first is replaced.
2972
+ - `upsert` (optional): When ``True``, inserts a new document if no
2973
+ document matches the query. Defaults to ``False``.
2974
+ - `return_document`: If
2975
+ :attr:`ReturnDocument.BEFORE` (the default),
2976
+ returns the original document before it was replaced, or ``None``
2977
+ if no document matches. If
2978
+ :attr:`ReturnDocument.AFTER`, returns the replaced
2979
+ or inserted document.
2980
+ - `hint` (optional): An index to use to support the query
2981
+ predicate specified either by its string name, or in the same
2982
+ format as passed to
2983
+ :meth:`~pymongo.collection.Collection.create_index` (e.g.
2984
+ ``[('field', ASCENDING)]``). This option is only supported on
2985
+ MongoDB 4.4 and above.
2986
+ - `session` (optional): a
2987
+ :class:`~pymongo.client_session.ClientSession`.
2988
+ - `let` (optional): Map of parameter names and values. Values must be
2989
+ constant or closed expressions that do not reference document
2990
+ fields. Parameters can then be accessed as variables in an
2991
+ aggregate expression context (e.g. "$$var").
2992
+ - `comment` (optional): A user-provided comment to attach to this
2993
+ command.
2994
+ - `**kwargs` (optional): additional command arguments can be passed
2995
+ as keyword arguments (for example maxTimeMS can be used with
2996
+ recent server versions).
2997
+
2998
+ .. versionchanged:: 4.1
2999
+ Added ``let`` parameter.
3000
+ .. versionchanged:: 3.11
3001
+ Added the ``hint`` option.
3002
+ .. versionchanged:: 3.6
3003
+ Added ``session`` parameter.
3004
+ .. versionchanged:: 3.4
3005
+ Added the ``collation`` option.
3006
+ .. versionchanged:: 3.2
3007
+ Respects write concern.
3008
+
3009
+ .. warning:: Starting in PyMongo 3.2, this command uses the
3010
+ :class:`~pymongo.write_concern.WriteConcern` of this
3011
+ :class:`~pymongo.collection.Collection` when connected to MongoDB >=
3012
+ 3.2. Note that using an elevated write concern with this command may
3013
+ be slower compared to using the default write concern.
3014
+
3015
+ .. versionadded:: 3.0
3016
+ """
3017
+ common.validate_ok_for_replace(replacement)
3018
+ kwargs["update"] = replacement
3019
+ if comment is not None:
3020
+ kwargs["comment"] = comment
3021
+ return self.__find_and_modify(
3022
+ filter,
3023
+ projection,
3024
+ sort,
3025
+ upsert,
3026
+ return_document,
3027
+ let=let,
3028
+ hint=hint,
3029
+ session=session,
3030
+ **kwargs,
3031
+ )
3032
+
3033
+ def find_one_and_update(
3034
+ self,
3035
+ filter: Mapping[str, Any],
3036
+ update: Union[Mapping[str, Any], _Pipeline],
3037
+ projection: Optional[Union[Mapping[str, Any], Iterable[str]]] = None,
3038
+ sort: Optional[_IndexList] = None,
3039
+ upsert: bool = False,
3040
+ return_document: bool = ReturnDocument.BEFORE,
3041
+ array_filters: Optional[Sequence[Mapping[str, Any]]] = None,
3042
+ hint: Optional[_IndexKeyHint] = None,
3043
+ session: Optional["ClientSession"] = None,
3044
+ let: Optional[Mapping[str, Any]] = None,
3045
+ comment: Optional[Any] = None,
3046
+ **kwargs: Any,
3047
+ ) -> _DocumentType:
3048
+ """Finds a single document and updates it, returning either the
3049
+ original or the updated document.
3050
+
3051
+ >>> db.test.find_one_and_update(
3052
+ ... {'_id': 665}, {'$inc': {'count': 1}, '$set': {'done': True}})
3053
+ {'_id': 665, 'done': False, 'count': 25}}
3054
+
3055
+ Returns ``None`` if no document matches the filter.
3056
+
3057
+ >>> db.test.find_one_and_update(
3058
+ ... {'_exists': False}, {'$inc': {'count': 1}})
3059
+
3060
+ When the filter matches, by default :meth:`find_one_and_update`
3061
+ returns the original version of the document before the update was
3062
+ applied. To return the updated (or inserted in the case of
3063
+ *upsert*) version of the document instead, use the *return_document*
3064
+ option.
3065
+
3066
+ >>> from pymongo import ReturnDocument
3067
+ >>> db.example.find_one_and_update(
3068
+ ... {'_id': 'userid'},
3069
+ ... {'$inc': {'seq': 1}},
3070
+ ... return_document=ReturnDocument.AFTER)
3071
+ {'_id': 'userid', 'seq': 1}
3072
+
3073
+ You can limit the fields returned with the *projection* option.
3074
+
3075
+ >>> db.example.find_one_and_update(
3076
+ ... {'_id': 'userid'},
3077
+ ... {'$inc': {'seq': 1}},
3078
+ ... projection={'seq': True, '_id': False},
3079
+ ... return_document=ReturnDocument.AFTER)
3080
+ {'seq': 2}
3081
+
3082
+ The *upsert* option can be used to create the document if it doesn't
3083
+ already exist.
3084
+
3085
+ >>> db.example.delete_many({}).deleted_count
3086
+ 1
3087
+ >>> db.example.find_one_and_update(
3088
+ ... {'_id': 'userid'},
3089
+ ... {'$inc': {'seq': 1}},
3090
+ ... projection={'seq': True, '_id': False},
3091
+ ... upsert=True,
3092
+ ... return_document=ReturnDocument.AFTER)
3093
+ {'seq': 1}
3094
+
3095
+ If multiple documents match *filter*, a *sort* can be applied.
3096
+
3097
+ >>> for doc in db.test.find({'done': True}):
3098
+ ... print(doc)
3099
+ ...
3100
+ {'_id': 665, 'done': True, 'result': {'count': 26}}
3101
+ {'_id': 701, 'done': True, 'result': {'count': 17}}
3102
+ >>> db.test.find_one_and_update(
3103
+ ... {'done': True},
3104
+ ... {'$set': {'final': True}},
3105
+ ... sort=[('_id', pymongo.DESCENDING)])
3106
+ {'_id': 701, 'done': True, 'result': {'count': 17}}
3107
+
3108
+ :Parameters:
3109
+ - `filter`: A query that matches the document to update.
3110
+ - `update`: The update operations to apply.
3111
+ - `projection` (optional): A list of field names that should be
3112
+ returned in the result document or a mapping specifying the fields
3113
+ to include or exclude. If `projection` is a list "_id" will
3114
+ always be returned. Use a dict to exclude fields from
3115
+ the result (e.g. projection={'_id': False}).
3116
+ - `sort` (optional): a list of (key, direction) pairs
3117
+ specifying the sort order for the query. If multiple documents
3118
+ match the query, they are sorted and the first is updated.
3119
+ - `upsert` (optional): When ``True``, inserts a new document if no
3120
+ document matches the query. Defaults to ``False``.
3121
+ - `return_document`: If
3122
+ :attr:`ReturnDocument.BEFORE` (the default),
3123
+ returns the original document before it was updated. If
3124
+ :attr:`ReturnDocument.AFTER`, returns the updated
3125
+ or inserted document.
3126
+ - `array_filters` (optional): A list of filters specifying which
3127
+ array elements an update should apply.
3128
+ - `hint` (optional): An index to use to support the query
3129
+ predicate specified either by its string name, or in the same
3130
+ format as passed to
3131
+ :meth:`~pymongo.collection.Collection.create_index` (e.g.
3132
+ ``[('field', ASCENDING)]``). This option is only supported on
3133
+ MongoDB 4.4 and above.
3134
+ - `session` (optional): a
3135
+ :class:`~pymongo.client_session.ClientSession`.
3136
+ - `let` (optional): Map of parameter names and values. Values must be
3137
+ constant or closed expressions that do not reference document
3138
+ fields. Parameters can then be accessed as variables in an
3139
+ aggregate expression context (e.g. "$$var").
3140
+ - `comment` (optional): A user-provided comment to attach to this
3141
+ command.
3142
+ - `**kwargs` (optional): additional command arguments can be passed
3143
+ as keyword arguments (for example maxTimeMS can be used with
3144
+ recent server versions).
3145
+
3146
+ .. versionchanged:: 3.11
3147
+ Added the ``hint`` option.
3148
+ .. versionchanged:: 3.9
3149
+ Added the ability to accept a pipeline as the ``update``.
3150
+ .. versionchanged:: 3.6
3151
+ Added the ``array_filters`` and ``session`` options.
3152
+ .. versionchanged:: 3.4
3153
+ Added the ``collation`` option.
3154
+ .. versionchanged:: 3.2
3155
+ Respects write concern.
3156
+
3157
+ .. warning:: Starting in PyMongo 3.2, this command uses the
3158
+ :class:`~pymongo.write_concern.WriteConcern` of this
3159
+ :class:`~pymongo.collection.Collection` when connected to MongoDB >=
3160
+ 3.2. Note that using an elevated write concern with this command may
3161
+ be slower compared to using the default write concern.
3162
+
3163
+ .. versionadded:: 3.0
3164
+ """
3165
+ common.validate_ok_for_update(update)
3166
+ common.validate_list_or_none("array_filters", array_filters)
3167
+ kwargs["update"] = update
3168
+ if comment is not None:
3169
+ kwargs["comment"] = comment
3170
+ return self.__find_and_modify(
3171
+ filter,
3172
+ projection,
3173
+ sort,
3174
+ upsert,
3175
+ return_document,
3176
+ array_filters,
3177
+ hint=hint,
3178
+ let=let,
3179
+ session=session,
3180
+ **kwargs,
3181
+ )
3182
+
3183
+ # See PYTHON-3084.
3184
+ __iter__ = None
3185
+
3186
+ def __next__(self) -> NoReturn:
3187
+ raise TypeError("'Collection' object is not iterable")
3188
+
3189
+ next = __next__
3190
+
3191
+ def __call__(self, *args: Any, **kwargs: Any) -> NoReturn:
3192
+ """This is only here so that some API misusages are easier to debug."""
3193
+ if "." not in self.__name:
3194
+ raise TypeError(
3195
+ "'Collection' object is not callable. If you "
3196
+ "meant to call the '%s' method on a 'Database' "
3197
+ "object it is failing because no such method "
3198
+ "exists." % self.__name
3199
+ )
3200
+ raise TypeError(
3201
+ "'Collection' object is not callable. If you meant to "
3202
+ "call the '%s' method on a 'Collection' object it is "
3203
+ "failing because no such method exists." % self.__name.split(".")[-1]
3204
+ )