operations.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. # Copyright 2015-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. """Operation class definitions."""
  15. from bson.py3compat import string_type
  16. from pymongo import helpers
  17. from pymongo.common import validate_boolean, validate_is_mapping, validate_list
  18. from pymongo.collation import validate_collation_or_none
  19. from pymongo.helpers import _gen_index_name, _index_document, _index_list
  20. class InsertOne(object):
  21. """Represents an insert_one operation."""
  22. __slots__ = ("_doc",)
  23. def __init__(self, document):
  24. """Create an InsertOne instance.
  25. For use with :meth:`~pymongo.collection.Collection.bulk_write`.
  26. :Parameters:
  27. - `document`: The document to insert. If the document is missing an
  28. _id field one will be added.
  29. """
  30. self._doc = document
  31. def _add_to_bulk(self, bulkobj):
  32. """Add this operation to the _Bulk instance `bulkobj`."""
  33. bulkobj.add_insert(self._doc)
  34. def __repr__(self):
  35. return "InsertOne(%r)" % (self._doc,)
  36. def __eq__(self, other):
  37. if type(other) == type(self):
  38. return other._doc == self._doc
  39. return NotImplemented
  40. def __ne__(self, other):
  41. return not self == other
  42. class DeleteOne(object):
  43. """Represents a delete_one operation."""
  44. __slots__ = ("_filter", "_collation", "_hint")
  45. def __init__(self, filter, collation=None, hint=None):
  46. """Create a DeleteOne instance.
  47. For use with :meth:`~pymongo.collection.Collection.bulk_write`.
  48. :Parameters:
  49. - `filter`: A query that matches the document to delete.
  50. - `collation` (optional): An instance of
  51. :class:`~pymongo.collation.Collation`. This option is only
  52. supported on MongoDB 3.4 and above.
  53. - `hint` (optional): An index to use to support the query
  54. predicate specified either by its string name, or in the same
  55. format as passed to
  56. :meth:`~pymongo.collection.Collection.create_index` (e.g.
  57. ``[('field', ASCENDING)]``). This option is only supported on
  58. MongoDB 4.4 and above.
  59. .. versionchanged:: 3.11
  60. Added the ``hint`` option.
  61. .. versionchanged:: 3.5
  62. Added the `collation` option.
  63. """
  64. if filter is not None:
  65. validate_is_mapping("filter", filter)
  66. if hint is not None:
  67. if not isinstance(hint, string_type):
  68. hint = helpers._index_document(hint)
  69. self._filter = filter
  70. self._collation = collation
  71. self._hint = hint
  72. def _add_to_bulk(self, bulkobj):
  73. """Add this operation to the _Bulk instance `bulkobj`."""
  74. bulkobj.add_delete(self._filter, 1, collation=self._collation,
  75. hint=self._hint)
  76. def __repr__(self):
  77. return "DeleteOne(%r, %r)" % (self._filter, self._collation)
  78. def __eq__(self, other):
  79. if type(other) == type(self):
  80. return ((other._filter, other._collation) ==
  81. (self._filter, self._collation))
  82. return NotImplemented
  83. def __ne__(self, other):
  84. return not self == other
  85. class DeleteMany(object):
  86. """Represents a delete_many operation."""
  87. __slots__ = ("_filter", "_collation", "_hint")
  88. def __init__(self, filter, collation=None, hint=None):
  89. """Create a DeleteMany instance.
  90. For use with :meth:`~pymongo.collection.Collection.bulk_write`.
  91. :Parameters:
  92. - `filter`: A query that matches the documents to delete.
  93. - `collation` (optional): An instance of
  94. :class:`~pymongo.collation.Collation`. This option is only
  95. supported on MongoDB 3.4 and above.
  96. - `hint` (optional): An index to use to support the query
  97. predicate specified either by its string name, or in the same
  98. format as passed to
  99. :meth:`~pymongo.collection.Collection.create_index` (e.g.
  100. ``[('field', ASCENDING)]``). This option is only supported on
  101. MongoDB 4.4 and above.
  102. .. versionchanged:: 3.11
  103. Added the ``hint`` option.
  104. .. versionchanged:: 3.5
  105. Added the `collation` option.
  106. """
  107. if filter is not None:
  108. validate_is_mapping("filter", filter)
  109. if hint is not None:
  110. if not isinstance(hint, string_type):
  111. hint = helpers._index_document(hint)
  112. self._filter = filter
  113. self._collation = collation
  114. self._hint = hint
  115. def _add_to_bulk(self, bulkobj):
  116. """Add this operation to the _Bulk instance `bulkobj`."""
  117. bulkobj.add_delete(self._filter, 0, collation=self._collation,
  118. hint=self._hint)
  119. def __repr__(self):
  120. return "DeleteMany(%r, %r)" % (self._filter, self._collation)
  121. def __eq__(self, other):
  122. if type(other) == type(self):
  123. return ((other._filter, other._collation) ==
  124. (self._filter, self._collation))
  125. return NotImplemented
  126. def __ne__(self, other):
  127. return not self == other
  128. class ReplaceOne(object):
  129. """Represents a replace_one operation."""
  130. __slots__ = ("_filter", "_doc", "_upsert", "_collation", "_hint")
  131. def __init__(self, filter, replacement, upsert=False, collation=None,
  132. hint=None):
  133. """Create a ReplaceOne instance.
  134. For use with :meth:`~pymongo.collection.Collection.bulk_write`.
  135. :Parameters:
  136. - `filter`: A query that matches the document to replace.
  137. - `replacement`: The new document.
  138. - `upsert` (optional): If ``True``, perform an insert if no documents
  139. match the filter.
  140. - `collation` (optional): An instance of
  141. :class:`~pymongo.collation.Collation`. This option is only
  142. supported on MongoDB 3.4 and above.
  143. - `hint` (optional): An index to use to support the query
  144. predicate specified either by its string name, or in the same
  145. format as passed to
  146. :meth:`~pymongo.collection.Collection.create_index` (e.g.
  147. ``[('field', ASCENDING)]``). This option is only supported on
  148. MongoDB 4.2 and above.
  149. .. versionchanged:: 3.11
  150. Added the ``hint`` option.
  151. .. versionchanged:: 3.5
  152. Added the ``collation`` option.
  153. """
  154. if filter is not None:
  155. validate_is_mapping("filter", filter)
  156. if upsert is not None:
  157. validate_boolean("upsert", upsert)
  158. if hint is not None:
  159. if not isinstance(hint, string_type):
  160. hint = helpers._index_document(hint)
  161. self._filter = filter
  162. self._doc = replacement
  163. self._upsert = upsert
  164. self._collation = collation
  165. self._hint = hint
  166. def _add_to_bulk(self, bulkobj):
  167. """Add this operation to the _Bulk instance `bulkobj`."""
  168. bulkobj.add_replace(self._filter, self._doc, self._upsert,
  169. collation=self._collation, hint=self._hint)
  170. def __eq__(self, other):
  171. if type(other) == type(self):
  172. return (
  173. (other._filter, other._doc, other._upsert, other._collation,
  174. other._hint) == (self._filter, self._doc, self._upsert,
  175. self._collation, other._hint))
  176. return NotImplemented
  177. def __ne__(self, other):
  178. return not self == other
  179. def __repr__(self):
  180. return "%s(%r, %r, %r, %r, %r)" % (
  181. self.__class__.__name__, self._filter, self._doc, self._upsert,
  182. self._collation, self._hint)
  183. class _UpdateOp(object):
  184. """Private base class for update operations."""
  185. __slots__ = ("_filter", "_doc", "_upsert", "_collation", "_array_filters",
  186. "_hint")
  187. def __init__(self, filter, doc, upsert, collation, array_filters, hint):
  188. if filter is not None:
  189. validate_is_mapping("filter", filter)
  190. if upsert is not None:
  191. validate_boolean("upsert", upsert)
  192. if array_filters is not None:
  193. validate_list("array_filters", array_filters)
  194. if hint is not None:
  195. if not isinstance(hint, string_type):
  196. hint = helpers._index_document(hint)
  197. self._filter = filter
  198. self._doc = doc
  199. self._upsert = upsert
  200. self._collation = collation
  201. self._array_filters = array_filters
  202. self._hint = hint
  203. def __eq__(self, other):
  204. if type(other) == type(self):
  205. return (
  206. (other._filter, other._doc, other._upsert, other._collation,
  207. other._array_filters, other._hint) ==
  208. (self._filter, self._doc, self._upsert, self._collation,
  209. self._array_filters, self._hint))
  210. return NotImplemented
  211. def __ne__(self, other):
  212. return not self == other
  213. def __repr__(self):
  214. return "%s(%r, %r, %r, %r, %r, %r)" % (
  215. self.__class__.__name__, self._filter, self._doc, self._upsert,
  216. self._collation, self._array_filters, self._hint)
  217. class UpdateOne(_UpdateOp):
  218. """Represents an update_one operation."""
  219. __slots__ = ()
  220. def __init__(self, filter, update, upsert=False, collation=None,
  221. array_filters=None, hint=None):
  222. """Represents an update_one operation.
  223. For use with :meth:`~pymongo.collection.Collection.bulk_write`.
  224. :Parameters:
  225. - `filter`: A query that matches the document to update.
  226. - `update`: The modifications to apply.
  227. - `upsert` (optional): If ``True``, perform an insert if no documents
  228. match the filter.
  229. - `collation` (optional): An instance of
  230. :class:`~pymongo.collation.Collation`. This option is only
  231. supported on MongoDB 3.4 and above.
  232. - `array_filters` (optional): A list of filters specifying which
  233. array elements an update should apply. Requires MongoDB 3.6+.
  234. - `hint` (optional): An index to use to support the query
  235. predicate specified either by its string name, or in the same
  236. format as passed to
  237. :meth:`~pymongo.collection.Collection.create_index` (e.g.
  238. ``[('field', ASCENDING)]``). This option is only supported on
  239. MongoDB 4.2 and above.
  240. .. versionchanged:: 3.11
  241. Added the `hint` option.
  242. .. versionchanged:: 3.9
  243. Added the ability to accept a pipeline as the `update`.
  244. .. versionchanged:: 3.6
  245. Added the `array_filters` option.
  246. .. versionchanged:: 3.5
  247. Added the `collation` option.
  248. """
  249. super(UpdateOne, self).__init__(filter, update, upsert, collation,
  250. array_filters, hint)
  251. def _add_to_bulk(self, bulkobj):
  252. """Add this operation to the _Bulk instance `bulkobj`."""
  253. bulkobj.add_update(self._filter, self._doc, False, self._upsert,
  254. collation=self._collation,
  255. array_filters=self._array_filters,
  256. hint=self._hint)
  257. class UpdateMany(_UpdateOp):
  258. """Represents an update_many operation."""
  259. __slots__ = ()
  260. def __init__(self, filter, update, upsert=False, collation=None,
  261. array_filters=None, hint=None):
  262. """Create an UpdateMany instance.
  263. For use with :meth:`~pymongo.collection.Collection.bulk_write`.
  264. :Parameters:
  265. - `filter`: A query that matches the documents to update.
  266. - `update`: The modifications to apply.
  267. - `upsert` (optional): If ``True``, perform an insert if no documents
  268. match the filter.
  269. - `collation` (optional): An instance of
  270. :class:`~pymongo.collation.Collation`. This option is only
  271. supported on MongoDB 3.4 and above.
  272. - `array_filters` (optional): A list of filters specifying which
  273. array elements an update should apply. Requires MongoDB 3.6+.
  274. - `hint` (optional): An index to use to support the query
  275. predicate specified either by its string name, or in the same
  276. format as passed to
  277. :meth:`~pymongo.collection.Collection.create_index` (e.g.
  278. ``[('field', ASCENDING)]``). This option is only supported on
  279. MongoDB 4.2 and above.
  280. .. versionchanged:: 3.11
  281. Added the `hint` option.
  282. .. versionchanged:: 3.9
  283. Added the ability to accept a pipeline as the `update`.
  284. .. versionchanged:: 3.6
  285. Added the `array_filters` option.
  286. .. versionchanged:: 3.5
  287. Added the `collation` option.
  288. """
  289. super(UpdateMany, self).__init__(filter, update, upsert, collation,
  290. array_filters, hint)
  291. def _add_to_bulk(self, bulkobj):
  292. """Add this operation to the _Bulk instance `bulkobj`."""
  293. bulkobj.add_update(self._filter, self._doc, True, self._upsert,
  294. collation=self._collation,
  295. array_filters=self._array_filters,
  296. hint=self._hint)
  297. class IndexModel(object):
  298. """Represents an index to create."""
  299. __slots__ = ("__document",)
  300. def __init__(self, keys, **kwargs):
  301. """Create an Index instance.
  302. For use with :meth:`~pymongo.collection.Collection.create_indexes`.
  303. Takes either a single key or a list of (key, direction) pairs.
  304. The key(s) must be an instance of :class:`basestring`
  305. (:class:`str` in python 3), and the direction(s) must be one of
  306. (:data:`~pymongo.ASCENDING`, :data:`~pymongo.DESCENDING`,
  307. :data:`~pymongo.GEO2D`, :data:`~pymongo.GEOHAYSTACK`,
  308. :data:`~pymongo.GEOSPHERE`, :data:`~pymongo.HASHED`,
  309. :data:`~pymongo.TEXT`).
  310. Valid options include, but are not limited to:
  311. - `name`: custom name to use for this index - if none is
  312. given, a name will be generated.
  313. - `unique`: if ``True``, creates a uniqueness constraint on the index.
  314. - `background`: if ``True``, this index should be created in the
  315. background.
  316. - `sparse`: if ``True``, omit from the index any documents that lack
  317. the indexed field.
  318. - `bucketSize`: for use with geoHaystack indexes.
  319. Number of documents to group together within a certain proximity
  320. to a given longitude and latitude.
  321. - `min`: minimum value for keys in a :data:`~pymongo.GEO2D`
  322. index.
  323. - `max`: maximum value for keys in a :data:`~pymongo.GEO2D`
  324. index.
  325. - `expireAfterSeconds`: <int> Used to create an expiring (TTL)
  326. collection. MongoDB will automatically delete documents from
  327. this collection after <int> seconds. The indexed field must
  328. be a UTC datetime or the data will not expire.
  329. - `partialFilterExpression`: A document that specifies a filter for
  330. a partial index. Requires MongoDB >= 3.2.
  331. - `collation`: An instance of :class:`~pymongo.collation.Collation`
  332. that specifies the collation to use in MongoDB >= 3.4.
  333. - `wildcardProjection`: Allows users to include or exclude specific
  334. field paths from a `wildcard index`_ using the { "$**" : 1} key
  335. pattern. Requires MongoDB >= 4.2.
  336. - `hidden`: if ``True``, this index will be hidden from the query
  337. planner and will not be evaluated as part of query plan
  338. selection. Requires MongoDB >= 4.4.
  339. See the MongoDB documentation for a full list of supported options by
  340. server version.
  341. :Parameters:
  342. - `keys`: a single key or a list of (key, direction)
  343. pairs specifying the index to create
  344. - `**kwargs` (optional): any additional index creation
  345. options (see the above list) should be passed as keyword
  346. arguments
  347. .. versionchanged:: 3.11
  348. Added the ``hidden`` option.
  349. .. versionchanged:: 3.2
  350. Added the ``partialFilterExpression`` option to support partial
  351. indexes.
  352. .. _wildcard index: https://docs.mongodb.com/master/core/index-wildcard/#wildcard-index-core
  353. """
  354. keys = _index_list(keys)
  355. if "name" not in kwargs:
  356. kwargs["name"] = _gen_index_name(keys)
  357. kwargs["key"] = _index_document(keys)
  358. collation = validate_collation_or_none(kwargs.pop('collation', None))
  359. self.__document = kwargs
  360. if collation is not None:
  361. self.__document['collation'] = collation
  362. @property
  363. def document(self):
  364. """An index document suitable for passing to the createIndexes
  365. command.
  366. """
  367. return self.__document