collection.py 149 KB

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