database.py 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111
  1. # Copyright 2009-2015 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. """Database level operations."""
  15. import warnings
  16. from bson.code import Code
  17. from bson.codec_options import CodecOptions
  18. from bson.dbref import DBRef
  19. from bson.objectid import ObjectId
  20. from bson.py3compat import iteritems, string_type, _unicode
  21. from bson.son import SON
  22. from pymongo import auth, common
  23. from pymongo.collection import Collection
  24. from pymongo.command_cursor import CommandCursor
  25. from pymongo.errors import (CollectionInvalid,
  26. ConfigurationError,
  27. InvalidName,
  28. OperationFailure)
  29. from pymongo.helpers import _first_batch
  30. from pymongo.read_preferences import ReadPreference
  31. from pymongo.son_manipulator import SONManipulator
  32. from pymongo.write_concern import WriteConcern
  33. def _check_name(name):
  34. """Check if a database name is valid.
  35. """
  36. if not name:
  37. raise InvalidName("database name cannot be the empty string")
  38. for invalid_char in [" ", ".", "$", "/", "\\", "\x00"]:
  39. if invalid_char in name:
  40. raise InvalidName("database names cannot contain the "
  41. "character %r" % invalid_char)
  42. class Database(common.BaseObject):
  43. """A Mongo database.
  44. """
  45. def __init__(self, client, name, codec_options=None,
  46. read_preference=None, write_concern=None):
  47. """Get a database by client and name.
  48. Raises :class:`TypeError` if `name` is not an instance of
  49. :class:`basestring` (:class:`str` in python 3). Raises
  50. :class:`~pymongo.errors.InvalidName` if `name` is not a valid
  51. database name.
  52. :Parameters:
  53. - `client`: A :class:`~pymongo.mongo_client.MongoClient` instance.
  54. - `name`: The database name.
  55. - `codec_options` (optional): An instance of
  56. :class:`~bson.codec_options.CodecOptions`. If ``None`` (the
  57. default) client.codec_options is used.
  58. - `read_preference` (optional): The read preference to use. If
  59. ``None`` (the default) client.read_preference is used.
  60. - `write_concern` (optional): An instance of
  61. :class:`~pymongo.write_concern.WriteConcern`. If ``None`` (the
  62. default) client.write_concern is used.
  63. .. mongodoc:: databases
  64. .. versionchanged:: 3.0
  65. Added the codec_options, read_preference, and write_concern options.
  66. :class:`~pymongo.database.Database` no longer returns an instance
  67. of :class:`~pymongo.collection.Collection` for attribute names
  68. with leading underscores. You must use dict-style lookups instead::
  69. db['__my_collection__']
  70. Not:
  71. db.__my_collection__
  72. """
  73. super(Database, self).__init__(
  74. codec_options or client.codec_options,
  75. read_preference or client.read_preference,
  76. write_concern or client.write_concern)
  77. if not isinstance(name, string_type):
  78. raise TypeError("name must be an instance "
  79. "of %s" % (string_type.__name__,))
  80. if name != '$external':
  81. _check_name(name)
  82. self.__name = _unicode(name)
  83. self.__client = client
  84. self.__incoming_manipulators = []
  85. self.__incoming_copying_manipulators = []
  86. self.__outgoing_manipulators = []
  87. self.__outgoing_copying_manipulators = []
  88. def add_son_manipulator(self, manipulator):
  89. """Add a new son manipulator to this database.
  90. **DEPRECATED** - `add_son_manipulator` is deprecated.
  91. .. versionchanged:: 3.0
  92. Deprecated add_son_manipulator.
  93. """
  94. warnings.warn("add_son_manipulator is deprecated",
  95. DeprecationWarning, stacklevel=2)
  96. base = SONManipulator()
  97. def method_overwritten(instance, method):
  98. """Test if this method has been overridden."""
  99. return (getattr(
  100. instance, method).__func__ != getattr(base, method).__func__)
  101. if manipulator.will_copy():
  102. if method_overwritten(manipulator, "transform_incoming"):
  103. self.__incoming_copying_manipulators.insert(0, manipulator)
  104. if method_overwritten(manipulator, "transform_outgoing"):
  105. self.__outgoing_copying_manipulators.insert(0, manipulator)
  106. else:
  107. if method_overwritten(manipulator, "transform_incoming"):
  108. self.__incoming_manipulators.insert(0, manipulator)
  109. if method_overwritten(manipulator, "transform_outgoing"):
  110. self.__outgoing_manipulators.insert(0, manipulator)
  111. @property
  112. def system_js(self):
  113. """A :class:`SystemJS` helper for this :class:`Database`.
  114. See the documentation for :class:`SystemJS` for more details.
  115. """
  116. return SystemJS(self)
  117. @property
  118. def client(self):
  119. """The client instance for this :class:`Database`."""
  120. return self.__client
  121. @property
  122. def name(self):
  123. """The name of this :class:`Database`."""
  124. return self.__name
  125. @property
  126. def incoming_manipulators(self):
  127. """All incoming SON manipulators installed on this instance.
  128. .. versionadded:: 2.0
  129. """
  130. return [manipulator.__class__.__name__
  131. for manipulator in self.__incoming_manipulators]
  132. @property
  133. def incoming_copying_manipulators(self):
  134. """All incoming SON copying manipulators installed on this instance.
  135. .. versionadded:: 2.0
  136. """
  137. return [manipulator.__class__.__name__
  138. for manipulator in self.__incoming_copying_manipulators]
  139. @property
  140. def outgoing_manipulators(self):
  141. """List all outgoing SON manipulators
  142. installed on this instance.
  143. .. versionadded:: 2.0
  144. """
  145. return [manipulator.__class__.__name__
  146. for manipulator in self.__outgoing_manipulators]
  147. @property
  148. def outgoing_copying_manipulators(self):
  149. """List all outgoing SON copying manipulators
  150. installed on this instance.
  151. .. versionadded:: 2.0
  152. """
  153. return [manipulator.__class__.__name__
  154. for manipulator in self.__outgoing_copying_manipulators]
  155. def __eq__(self, other):
  156. if isinstance(other, Database):
  157. return (self.__client == other.client and
  158. self.__name == other.name)
  159. return NotImplemented
  160. def __ne__(self, other):
  161. return not self == other
  162. def __repr__(self):
  163. return "Database(%r, %r)" % (self.__client, self.__name)
  164. def __getattr__(self, name):
  165. """Get a collection of this database by name.
  166. Raises InvalidName if an invalid collection name is used.
  167. :Parameters:
  168. - `name`: the name of the collection to get
  169. """
  170. if name.startswith('_'):
  171. raise AttributeError(
  172. "Database has no attribute %r. To access the %s"
  173. " collection, use database[%r]." % (name, name, name))
  174. return self.__getitem__(name)
  175. def __getitem__(self, name):
  176. """Get a collection of this database by name.
  177. Raises InvalidName if an invalid collection name is used.
  178. :Parameters:
  179. - `name`: the name of the collection to get
  180. """
  181. return Collection(self, name)
  182. def get_collection(self, name, codec_options=None,
  183. read_preference=None, write_concern=None):
  184. """Get a :class:`~pymongo.collection.Collection` with the given name
  185. and options.
  186. Useful for creating a :class:`~pymongo.collection.Collection` with
  187. different codec options, read preference, and/or write concern from
  188. this :class:`Database`.
  189. >>> db.read_preference
  190. Primary()
  191. >>> coll1 = db.test
  192. >>> coll1.read_preference
  193. Primary()
  194. >>> from pymongo import ReadPreference
  195. >>> coll2 = db.get_collection(
  196. ... 'test', read_preference=ReadPreference.SECONDARY)
  197. >>> coll2.read_preference
  198. Secondary(tag_sets=None)
  199. :Parameters:
  200. - `name`: The name of the collection - a string.
  201. - `codec_options` (optional): An instance of
  202. :class:`~bson.codec_options.CodecOptions`. If ``None`` (the
  203. default) the :attr:`codec_options` of this :class:`Database` is
  204. used.
  205. - `read_preference` (optional): The read preference to use. If
  206. ``None`` (the default) the :attr:`read_preference` of this
  207. :class:`Database` is used. See :mod:`~pymongo.read_preferences`
  208. for options.
  209. - `write_concern` (optional): An instance of
  210. :class:`~pymongo.write_concern.WriteConcern`. If ``None`` (the
  211. default) the :attr:`write_concern` of this :class:`Database` is
  212. used.
  213. """
  214. return Collection(
  215. self, name, False, codec_options, read_preference, write_concern)
  216. def create_collection(self, name, codec_options=None,
  217. read_preference=None, write_concern=None, **kwargs):
  218. """Create a new :class:`~pymongo.collection.Collection` in this
  219. database.
  220. Normally collection creation is automatic. This method should
  221. only be used to specify options on
  222. creation. :class:`~pymongo.errors.CollectionInvalid` will be
  223. raised if the collection already exists.
  224. Options should be passed as keyword arguments to this method. Supported
  225. options vary with MongoDB release. Some examples include:
  226. - "size": desired initial size for the collection (in
  227. bytes). For capped collections this size is the max
  228. size of the collection.
  229. - "capped": if True, this is a capped collection
  230. - "max": maximum number of objects if capped (optional)
  231. See the MongoDB documentation for a full list of supported options by
  232. server version.
  233. :Parameters:
  234. - `name`: the name of the collection to create
  235. - `codec_options` (optional): An instance of
  236. :class:`~bson.codec_options.CodecOptions`. If ``None`` (the
  237. default) the :attr:`codec_options` of this :class:`Database` is
  238. used.
  239. - `read_preference` (optional): The read preference to use. If
  240. ``None`` (the default) the :attr:`read_preference` of this
  241. :class:`Database` is used.
  242. - `write_concern` (optional): An instance of
  243. :class:`~pymongo.write_concern.WriteConcern`. If ``None`` (the
  244. default) the :attr:`write_concern` of this :class:`Database` is
  245. used.
  246. - `**kwargs` (optional): additional keyword arguments will
  247. be passed as options for the create collection command
  248. .. versionchanged:: 3.0
  249. Added the codec_options, read_preference, and write_concern options.
  250. .. versionchanged:: 2.2
  251. Removed deprecated argument: options
  252. """
  253. if name in self.collection_names():
  254. raise CollectionInvalid("collection %s already exists" % name)
  255. return Collection(self, name, True, codec_options,
  256. read_preference, write_concern, **kwargs)
  257. def _apply_incoming_manipulators(self, son, collection):
  258. """Apply incoming manipulators to `son`."""
  259. for manipulator in self.__incoming_manipulators:
  260. son = manipulator.transform_incoming(son, collection)
  261. return son
  262. def _apply_incoming_copying_manipulators(self, son, collection):
  263. """Apply incoming copying manipulators to `son`."""
  264. for manipulator in self.__incoming_copying_manipulators:
  265. son = manipulator.transform_incoming(son, collection)
  266. return son
  267. def _fix_incoming(self, son, collection):
  268. """Apply manipulators to an incoming SON object before it gets stored.
  269. :Parameters:
  270. - `son`: the son object going into the database
  271. - `collection`: the collection the son object is being saved in
  272. """
  273. son = self._apply_incoming_manipulators(son, collection)
  274. son = self._apply_incoming_copying_manipulators(son, collection)
  275. return son
  276. def _fix_outgoing(self, son, collection):
  277. """Apply manipulators to a SON object as it comes out of the database.
  278. :Parameters:
  279. - `son`: the son object coming out of the database
  280. - `collection`: the collection the son object was saved in
  281. """
  282. for manipulator in reversed(self.__outgoing_manipulators):
  283. son = manipulator.transform_outgoing(son, collection)
  284. for manipulator in reversed(self.__outgoing_copying_manipulators):
  285. son = manipulator.transform_outgoing(son, collection)
  286. return son
  287. def _command(self, sock_info, command, slave_ok=False, value=1, check=True,
  288. allowable_errors=None, read_preference=ReadPreference.PRIMARY,
  289. codec_options=CodecOptions(), **kwargs):
  290. """Internal command helper."""
  291. if isinstance(command, string_type):
  292. command = SON([(command, value)])
  293. command.update(kwargs)
  294. return sock_info.command(self.__name,
  295. command,
  296. slave_ok,
  297. read_preference,
  298. codec_options,
  299. check,
  300. allowable_errors)
  301. def command(self, command, value=1, check=True,
  302. allowable_errors=None, read_preference=ReadPreference.PRIMARY,
  303. codec_options=CodecOptions(), **kwargs):
  304. """Issue a MongoDB command.
  305. Send command `command` to the database and return the
  306. response. If `command` is an instance of :class:`basestring`
  307. (:class:`str` in python 3) then the command {`command`: `value`}
  308. will be sent. Otherwise, `command` must be an instance of
  309. :class:`dict` and will be sent as is.
  310. Any additional keyword arguments will be added to the final
  311. command document before it is sent.
  312. For example, a command like ``{buildinfo: 1}`` can be sent
  313. using:
  314. >>> db.command("buildinfo")
  315. For a command where the value matters, like ``{collstats:
  316. collection_name}`` we can do:
  317. >>> db.command("collstats", collection_name)
  318. For commands that take additional arguments we can use
  319. kwargs. So ``{filemd5: object_id, root: file_root}`` becomes:
  320. >>> db.command("filemd5", object_id, root=file_root)
  321. :Parameters:
  322. - `command`: document representing the command to be issued,
  323. or the name of the command (for simple commands only).
  324. .. note:: the order of keys in the `command` document is
  325. significant (the "verb" must come first), so commands
  326. which require multiple keys (e.g. `findandmodify`)
  327. should use an instance of :class:`~bson.son.SON` or
  328. a string and kwargs instead of a Python `dict`.
  329. - `value` (optional): value to use for the command verb when
  330. `command` is passed as a string
  331. - `check` (optional): check the response for errors, raising
  332. :class:`~pymongo.errors.OperationFailure` if there are any
  333. - `allowable_errors`: if `check` is ``True``, error messages
  334. in this list will be ignored by error-checking
  335. - `read_preference`: The read preference for this operation.
  336. See :mod:`~pymongo.read_preferences` for options.
  337. - `codec_options`: A :class:`~bson.codec_options.CodecOptions`
  338. instance.
  339. - `**kwargs` (optional): additional keyword arguments will
  340. be added to the command document before it is sent
  341. .. note:: :meth:`command` does **not** obey :attr:`read_preference`
  342. or :attr:`codec_options`. You must use the `read_preference` and
  343. `codec_options` parameters instead.
  344. .. versionchanged:: 3.0
  345. Removed the `as_class`, `fields`, `uuid_subtype`, `tag_sets`,
  346. and `secondary_acceptable_latency_ms` option.
  347. Removed `compile_re` option: PyMongo now always represents BSON
  348. regular expressions as :class:`~bson.regex.Regex` objects. Use
  349. :meth:`~bson.regex.Regex.try_compile` to attempt to convert from a
  350. BSON regular expression to a Python regular expression object.
  351. Added the `codec_options` parameter.
  352. .. versionchanged:: 2.7
  353. Added `compile_re` option. If set to False, PyMongo represented BSON
  354. regular expressions as :class:`~bson.regex.Regex` objects instead of
  355. attempting to compile BSON regular expressions as Python native
  356. regular expressions, thus preventing errors for some incompatible
  357. patterns, see `PYTHON-500`_.
  358. .. versionchanged:: 2.3
  359. Added `tag_sets` and `secondary_acceptable_latency_ms` options.
  360. .. versionchanged:: 2.2
  361. Added support for `as_class` - the class you want to use for
  362. the resulting documents
  363. .. _PYTHON-500: https://jira.mongodb.org/browse/PYTHON-500
  364. .. mongodoc:: commands
  365. """
  366. client = self.__client
  367. with client._socket_for_reads(read_preference) as (sock_info, slave_ok):
  368. return self._command(sock_info, command, slave_ok, value,
  369. check, allowable_errors, read_preference,
  370. codec_options, **kwargs)
  371. def _list_collections(self, sock_info, slave_okay, criteria=None):
  372. """Internal listCollections helper."""
  373. criteria = criteria or {}
  374. if sock_info.max_wire_version > 2:
  375. cmd = SON([("listCollections", 1), ("cursor", {})])
  376. if criteria:
  377. cmd["filter"] = criteria
  378. coll = self["$cmd"]
  379. cursor = self._command(sock_info, cmd, slave_okay)["cursor"]
  380. return CommandCursor(coll, cursor, sock_info.address)
  381. else:
  382. coll = self["system.namespaces"]
  383. res = _first_batch(sock_info, coll.full_name,
  384. criteria, 0, slave_okay,
  385. CodecOptions(), ReadPreference.PRIMARY)
  386. data = res["data"]
  387. cursor = {
  388. "id": res["cursor_id"],
  389. "firstBatch": data,
  390. "ns": coll.full_name,
  391. }
  392. # Need to tell the cursor how many docs were in the first batch.
  393. return CommandCursor(coll, cursor, sock_info.address, len(data))
  394. def collection_names(self, include_system_collections=True):
  395. """Get a list of all the collection names in this database.
  396. :Parameters:
  397. - `include_system_collections` (optional): if ``False`` list
  398. will not include system collections (e.g ``system.indexes``)
  399. """
  400. with self.__client._socket_for_reads(
  401. ReadPreference.PRIMARY) as (sock_info, slave_okay):
  402. results = self._list_collections(sock_info, slave_okay)
  403. names = [result["name"] for result in results]
  404. if sock_info.max_wire_version <= 2:
  405. # MongoDB 2.4 and older return index namespaces and collection
  406. # namespaces prefixed with the database name.
  407. names = [n[len(self.__name) + 1:] for n in names
  408. if n.startswith(self.__name + ".") and "$" not in n]
  409. if not include_system_collections:
  410. names = [name for name in names if not name.startswith("system.")]
  411. return names
  412. def drop_collection(self, name_or_collection):
  413. """Drop a collection.
  414. :Parameters:
  415. - `name_or_collection`: the name of a collection to drop or the
  416. collection object itself
  417. """
  418. name = name_or_collection
  419. if isinstance(name, Collection):
  420. name = name.name
  421. if not isinstance(name, string_type):
  422. raise TypeError("name_or_collection must be an "
  423. "instance of %s" % (string_type.__name__,))
  424. self.__client._purge_index(self.__name, name)
  425. self.command("drop", _unicode(name), allowable_errors=["ns not found"])
  426. def validate_collection(self, name_or_collection,
  427. scandata=False, full=False):
  428. """Validate a collection.
  429. Returns a dict of validation info. Raises CollectionInvalid if
  430. validation fails.
  431. With MongoDB < 1.9 the result dict will include a `result` key
  432. with a string value that represents the validation results. With
  433. MongoDB >= 1.9 the `result` key no longer exists and the results
  434. are split into individual fields in the result dict.
  435. :Parameters:
  436. - `name_or_collection`: A Collection object or the name of a
  437. collection to validate.
  438. - `scandata`: Do extra checks beyond checking the overall
  439. structure of the collection.
  440. - `full`: Have the server do a more thorough scan of the
  441. collection. Use with `scandata` for a thorough scan
  442. of the structure of the collection and the individual
  443. documents. Ignored in MongoDB versions before 1.9.
  444. """
  445. name = name_or_collection
  446. if isinstance(name, Collection):
  447. name = name.name
  448. if not isinstance(name, string_type):
  449. raise TypeError("name_or_collection must be an instance of "
  450. "%s or Collection" % (string_type.__name__,))
  451. result = self.command("validate", _unicode(name),
  452. scandata=scandata, full=full)
  453. valid = True
  454. # Pre 1.9 results
  455. if "result" in result:
  456. info = result["result"]
  457. if info.find("exception") != -1 or info.find("corrupt") != -1:
  458. raise CollectionInvalid("%s invalid: %s" % (name, info))
  459. # Sharded results
  460. elif "raw" in result:
  461. for _, res in iteritems(result["raw"]):
  462. if "result" in res:
  463. info = res["result"]
  464. if (info.find("exception") != -1 or
  465. info.find("corrupt") != -1):
  466. raise CollectionInvalid("%s invalid: "
  467. "%s" % (name, info))
  468. elif not res.get("valid", False):
  469. valid = False
  470. break
  471. # Post 1.9 non-sharded results.
  472. elif not result.get("valid", False):
  473. valid = False
  474. if not valid:
  475. raise CollectionInvalid("%s invalid: %r" % (name, result))
  476. return result
  477. def current_op(self, include_all=False):
  478. """Get information on operations currently running.
  479. :Parameters:
  480. - `include_all` (optional): if ``True`` also list currently
  481. idle operations in the result
  482. """
  483. coll = self.get_collection(
  484. "$cmd.sys.inprog", read_preference=ReadPreference.PRIMARY)
  485. if include_all:
  486. return coll.find_one({"$all": True})
  487. else:
  488. return coll.find_one()
  489. def profiling_level(self):
  490. """Get the database's current profiling level.
  491. Returns one of (:data:`~pymongo.OFF`,
  492. :data:`~pymongo.SLOW_ONLY`, :data:`~pymongo.ALL`).
  493. .. mongodoc:: profiling
  494. """
  495. result = self.command("profile", -1)
  496. assert result["was"] >= 0 and result["was"] <= 2
  497. return result["was"]
  498. def set_profiling_level(self, level, slow_ms=None):
  499. """Set the database's profiling level.
  500. :Parameters:
  501. - `level`: Specifies a profiling level, see list of possible values
  502. below.
  503. - `slow_ms`: Optionally modify the threshold for the profile to
  504. consider a query or operation. Even if the profiler is off queries
  505. slower than the `slow_ms` level will get written to the logs.
  506. Possible `level` values:
  507. +----------------------------+------------------------------------+
  508. | Level | Setting |
  509. +============================+====================================+
  510. | :data:`~pymongo.OFF` | Off. No profiling. |
  511. +----------------------------+------------------------------------+
  512. | :data:`~pymongo.SLOW_ONLY` | On. Only includes slow operations. |
  513. +----------------------------+------------------------------------+
  514. | :data:`~pymongo.ALL` | On. Includes all operations. |
  515. +----------------------------+------------------------------------+
  516. Raises :class:`ValueError` if level is not one of
  517. (:data:`~pymongo.OFF`, :data:`~pymongo.SLOW_ONLY`,
  518. :data:`~pymongo.ALL`).
  519. .. mongodoc:: profiling
  520. """
  521. if not isinstance(level, int) or level < 0 or level > 2:
  522. raise ValueError("level must be one of (OFF, SLOW_ONLY, ALL)")
  523. if slow_ms is not None and not isinstance(slow_ms, int):
  524. raise TypeError("slow_ms must be an integer")
  525. if slow_ms is not None:
  526. self.command("profile", level, slowms=slow_ms)
  527. else:
  528. self.command("profile", level)
  529. def profiling_info(self):
  530. """Returns a list containing current profiling information.
  531. .. mongodoc:: profiling
  532. """
  533. return list(self["system.profile"].find())
  534. def error(self):
  535. """**DEPRECATED**: Get the error if one occurred on the last operation.
  536. This method is obsolete: all MongoDB write operations (insert, update,
  537. remove, and so on) use the write concern ``w=1`` and report their
  538. errors by default.
  539. .. versionchanged:: 2.8
  540. Deprecated.
  541. """
  542. warnings.warn("Database.error() is deprecated",
  543. DeprecationWarning, stacklevel=2)
  544. error = self.command("getlasterror")
  545. error_msg = error.get("err", "")
  546. if error_msg is None:
  547. return None
  548. if error_msg.startswith("not master"):
  549. # Reset primary server and request check, if another thread isn't
  550. # doing so already.
  551. primary = self.__client.primary
  552. if primary:
  553. self.__client._reset_server_and_request_check(primary)
  554. return error
  555. def last_status(self):
  556. """**DEPRECATED**: Get status information from the last operation.
  557. This method is obsolete: all MongoDB write operations (insert, update,
  558. remove, and so on) use the write concern ``w=1`` and report their
  559. errors by default.
  560. Returns a SON object with status information.
  561. .. versionchanged:: 2.8
  562. Deprecated.
  563. """
  564. warnings.warn("last_status() is deprecated",
  565. DeprecationWarning, stacklevel=2)
  566. return self.command("getlasterror")
  567. def previous_error(self):
  568. """**DEPRECATED**: Get the most recent error on this database.
  569. This method is obsolete: all MongoDB write operations (insert, update,
  570. remove, and so on) use the write concern ``w=1`` and report their
  571. errors by default.
  572. Only returns errors that have occurred since the last call to
  573. :meth:`reset_error_history`. Returns None if no such errors have
  574. occurred.
  575. .. versionchanged:: 2.8
  576. Deprecated.
  577. """
  578. warnings.warn("previous_error() is deprecated",
  579. DeprecationWarning, stacklevel=2)
  580. error = self.command("getpreverror")
  581. if error.get("err", 0) is None:
  582. return None
  583. return error
  584. def reset_error_history(self):
  585. """**DEPRECATED**: Reset the error history of this database.
  586. This method is obsolete: all MongoDB write operations (insert, update,
  587. remove, and so on) use the write concern ``w=1`` and report their
  588. errors by default.
  589. Calls to :meth:`previous_error` will only return errors that have
  590. occurred since the most recent call to this method.
  591. .. versionchanged:: 2.8
  592. Deprecated.
  593. """
  594. warnings.warn("reset_error_history() is deprecated",
  595. DeprecationWarning, stacklevel=2)
  596. self.command("reseterror")
  597. def __iter__(self):
  598. return self
  599. def __next__(self):
  600. raise TypeError("'Database' object is not iterable")
  601. next = __next__
  602. def _default_role(self, read_only):
  603. """Return the default user role for this database."""
  604. if self.name == "admin":
  605. if read_only:
  606. return "readAnyDatabase"
  607. else:
  608. return "root"
  609. else:
  610. if read_only:
  611. return "read"
  612. else:
  613. return "dbOwner"
  614. def _create_or_update_user(
  615. self, create, name, password, read_only, **kwargs):
  616. """Use a command to create (if create=True) or modify a user.
  617. """
  618. opts = {}
  619. if read_only or (create and "roles" not in kwargs):
  620. warnings.warn("Creating a user with the read_only option "
  621. "or without roles is deprecated in MongoDB "
  622. ">= 2.6", DeprecationWarning)
  623. opts["roles"] = [self._default_role(read_only)]
  624. elif read_only:
  625. warnings.warn("The read_only option is deprecated in MongoDB "
  626. ">= 2.6, use 'roles' instead", DeprecationWarning)
  627. if password is not None:
  628. # We always salt and hash client side.
  629. if "digestPassword" in kwargs:
  630. raise ConfigurationError("The digestPassword option is not "
  631. "supported via add_user. Please use "
  632. "db.command('createUser', ...) "
  633. "instead for this option.")
  634. opts["pwd"] = auth._password_digest(name, password)
  635. opts["digestPassword"] = False
  636. # Don't send {} as writeConcern.
  637. if self.write_concern.acknowledged and self.write_concern.document:
  638. opts["writeConcern"] = self.write_concern.document
  639. opts.update(kwargs)
  640. if create:
  641. command_name = "createUser"
  642. else:
  643. command_name = "updateUser"
  644. self.command(command_name, name, **opts)
  645. def _legacy_add_user(self, name, password, read_only, **kwargs):
  646. """Uses v1 system to add users, i.e. saving to system.users.
  647. """
  648. user = self.system.users.find_one({"user": name}) or {"user": name}
  649. if password is not None:
  650. user["pwd"] = auth._password_digest(name, password)
  651. if read_only is not None:
  652. user["readOnly"] = read_only
  653. user.update(kwargs)
  654. # We don't care what the _id is, only that it has one
  655. # for the replace_one call below.
  656. user.setdefault("_id", ObjectId())
  657. coll = self.system.users
  658. if not self.write_concern.acknowledged:
  659. coll = coll.with_options(write_concern=WriteConcern())
  660. try:
  661. coll.replace_one({"_id": user["_id"]}, user, True)
  662. except OperationFailure as exc:
  663. # First admin user add fails gle in MongoDB >= 2.1.2
  664. # See SERVER-4225 for more information.
  665. if 'login' in str(exc):
  666. pass
  667. # First admin user add fails gle from mongos 2.0.x
  668. # and 2.2.x.
  669. elif (exc.details and
  670. 'getlasterror' in exc.details.get('note', '')):
  671. pass
  672. else:
  673. raise
  674. def add_user(self, name, password=None, read_only=None, **kwargs):
  675. """Create user `name` with password `password`.
  676. Add a new user with permissions for this :class:`Database`.
  677. .. note:: Will change the password if user `name` already exists.
  678. :Parameters:
  679. - `name`: the name of the user to create
  680. - `password` (optional): the password of the user to create. Can not
  681. be used with the ``userSource`` argument.
  682. - `read_only` (optional): if ``True`` the user will be read only
  683. - `**kwargs` (optional): optional fields for the user document
  684. (e.g. ``userSource``, ``otherDBRoles``, or ``roles``). See
  685. `<http://docs.mongodb.org/manual/reference/privilege-documents>`_
  686. for more information.
  687. .. note:: The use of optional keyword arguments like ``userSource``,
  688. ``otherDBRoles``, or ``roles`` requires MongoDB >= 2.4.0
  689. .. versionchanged:: 2.5
  690. Added kwargs support for optional fields introduced in MongoDB 2.4
  691. .. versionchanged:: 2.2
  692. Added support for read only users
  693. """
  694. if not isinstance(name, string_type):
  695. raise TypeError("name must be an "
  696. "instance of %s" % (string_type.__name__,))
  697. if password is not None:
  698. if not isinstance(password, string_type):
  699. raise TypeError("password must be an "
  700. "instance of %s" % (string_type.__name__,))
  701. if len(password) == 0:
  702. raise ValueError("password can't be empty")
  703. if read_only is not None:
  704. read_only = common.validate_boolean('read_only', read_only)
  705. if 'roles' in kwargs:
  706. raise ConfigurationError("Can not use "
  707. "read_only and roles together")
  708. try:
  709. uinfo = self.command("usersInfo", name)
  710. # Create the user if not found in uinfo, otherwise update one.
  711. self._create_or_update_user(
  712. (not uinfo["users"]), name, password, read_only, **kwargs)
  713. except OperationFailure as exc:
  714. # MongoDB >= 2.5.3 requires the use of commands to manage
  715. # users.
  716. if exc.code in common.COMMAND_NOT_FOUND_CODES:
  717. self._legacy_add_user(name, password, read_only, **kwargs)
  718. return
  719. # Unauthorized. Attempt to create the user in case of
  720. # localhost exception.
  721. elif exc.code == 13:
  722. self._create_or_update_user(
  723. True, name, password, read_only, **kwargs)
  724. else:
  725. raise
  726. def remove_user(self, name):
  727. """Remove user `name` from this :class:`Database`.
  728. User `name` will no longer have permissions to access this
  729. :class:`Database`.
  730. :Parameters:
  731. - `name`: the name of the user to remove
  732. """
  733. try:
  734. cmd = SON([("dropUser", name)])
  735. # Don't send {} as writeConcern.
  736. if self.write_concern.acknowledged and self.write_concern.document:
  737. cmd["writeConcern"] = self.write_concern.document
  738. self.command(cmd)
  739. except OperationFailure as exc:
  740. # See comment in add_user try / except above.
  741. if exc.code in common.COMMAND_NOT_FOUND_CODES:
  742. coll = self.system.users
  743. if not self.write_concern.acknowledged:
  744. coll = coll.with_options(write_concern=WriteConcern())
  745. coll.delete_one({"user": name})
  746. return
  747. raise
  748. def authenticate(self, name, password=None,
  749. source=None, mechanism='DEFAULT', **kwargs):
  750. """Authenticate to use this database.
  751. Authentication lasts for the life of the underlying client
  752. instance, or until :meth:`logout` is called.
  753. Raises :class:`TypeError` if (required) `name`, (optional) `password`,
  754. or (optional) `source` is not an instance of :class:`basestring`
  755. (:class:`str` in python 3).
  756. .. note::
  757. - This method authenticates the current connection, and
  758. will also cause all new :class:`~socket.socket` connections
  759. in the underlying client instance to be authenticated automatically.
  760. - Authenticating more than once on the same database with different
  761. credentials is not supported. You must call :meth:`logout` before
  762. authenticating with new credentials.
  763. - When sharing a client instance between multiple threads, all
  764. threads will share the authentication. If you need different
  765. authentication profiles for different purposes you must use
  766. distinct client instances.
  767. :Parameters:
  768. - `name`: the name of the user to authenticate.
  769. - `password` (optional): the password of the user to authenticate.
  770. Not used with GSSAPI or MONGODB-X509 authentication.
  771. - `source` (optional): the database to authenticate on. If not
  772. specified the current database is used.
  773. - `mechanism` (optional): See
  774. :data:`~pymongo.auth.MECHANISMS` for options.
  775. By default, use SCRAM-SHA-1 with MongoDB 3.0 and later,
  776. MONGODB-CR (MongoDB Challenge Response protocol) for older servers.
  777. - `authMechanismProperties` (optional): Used to specify
  778. authentication mechanism specific options. To specify the service
  779. name for GSSAPI authentication pass
  780. authMechanismProperties='SERVICE_NAME:<service name>'
  781. .. versionadded:: 2.8
  782. Use SCRAM-SHA-1 with MongoDB 3.0 and later.
  783. .. versionchanged:: 2.5
  784. Added the `source` and `mechanism` parameters. :meth:`authenticate`
  785. now raises a subclass of :class:`~pymongo.errors.PyMongoError` if
  786. authentication fails due to invalid credentials or configuration
  787. issues.
  788. .. mongodoc:: authenticate
  789. """
  790. if not isinstance(name, string_type):
  791. raise TypeError("name must be an "
  792. "instance of %s" % (string_type.__name__,))
  793. if password is not None and not isinstance(password, string_type):
  794. raise TypeError("password must be an "
  795. "instance of %s" % (string_type.__name__,))
  796. if source is not None and not isinstance(source, string_type):
  797. raise TypeError("source must be an "
  798. "instance of %s" % (string_type.__name__,))
  799. common.validate_auth_mechanism('mechanism', mechanism)
  800. validated_options = {}
  801. for option, value in iteritems(kwargs):
  802. normalized, val = common.validate_auth_option(option, value)
  803. validated_options[normalized] = val
  804. credentials = auth._build_credentials_tuple(
  805. mechanism,
  806. source or self.name,
  807. name,
  808. password,
  809. validated_options)
  810. self.client._cache_credentials(
  811. self.name,
  812. credentials,
  813. connect=True)
  814. return True
  815. def logout(self):
  816. """Deauthorize use of this database for this client instance."""
  817. # Sockets will be deauthenticated as they are used.
  818. self.client._purge_credentials(self.name)
  819. def dereference(self, dbref, **kwargs):
  820. """Dereference a :class:`~bson.dbref.DBRef`, getting the
  821. document it points to.
  822. Raises :class:`TypeError` if `dbref` is not an instance of
  823. :class:`~bson.dbref.DBRef`. Returns a document, or ``None`` if
  824. the reference does not point to a valid document. Raises
  825. :class:`ValueError` if `dbref` has a database specified that
  826. is different from the current database.
  827. :Parameters:
  828. - `dbref`: the reference
  829. - `**kwargs` (optional): any additional keyword arguments
  830. are the same as the arguments to
  831. :meth:`~pymongo.collection.Collection.find`.
  832. """
  833. if not isinstance(dbref, DBRef):
  834. raise TypeError("cannot dereference a %s" % type(dbref))
  835. if dbref.database is not None and dbref.database != self.__name:
  836. raise ValueError("trying to dereference a DBRef that points to "
  837. "another database (%r not %r)" % (dbref.database,
  838. self.__name))
  839. return self[dbref.collection].find_one({"_id": dbref.id}, **kwargs)
  840. def eval(self, code, *args):
  841. """Evaluate a JavaScript expression in MongoDB.
  842. Useful if you need to touch a lot of data lightly; in such a
  843. scenario the network transfer of the data could be a
  844. bottleneck. The `code` argument must be a JavaScript
  845. function. Additional positional arguments will be passed to
  846. that function when it is run on the server.
  847. Raises :class:`TypeError` if `code` is not an instance of
  848. :class:`basestring` (:class:`str` in python 3) or `Code`.
  849. Raises :class:`~pymongo.errors.OperationFailure` if the eval
  850. fails. Returns the result of the evaluation.
  851. :Parameters:
  852. - `code`: string representation of JavaScript code to be
  853. evaluated
  854. - `args` (optional): additional positional arguments are
  855. passed to the `code` being evaluated
  856. """
  857. if not isinstance(code, Code):
  858. code = Code(code)
  859. result = self.command("$eval", code, args=args)
  860. return result.get("retval", None)
  861. def __call__(self, *args, **kwargs):
  862. """This is only here so that some API misusages are easier to debug.
  863. """
  864. raise TypeError("'Database' object is not callable. If you meant to "
  865. "call the '%s' method on a '%s' object it is "
  866. "failing because no such method exists." % (
  867. self.__name, self.__client.__class__.__name__))
  868. class SystemJS(object):
  869. """Helper class for dealing with stored JavaScript.
  870. """
  871. def __init__(self, database):
  872. """Get a system js helper for the database `database`.
  873. An instance of :class:`SystemJS` can be created with an instance
  874. of :class:`Database` through :attr:`Database.system_js`,
  875. manual instantiation of this class should not be necessary.
  876. :class:`SystemJS` instances allow for easy manipulation and
  877. access to server-side JavaScript:
  878. .. doctest::
  879. >>> db.system_js.add1 = "function (x) { return x + 1; }"
  880. >>> db.system.js.find({"_id": "add1"}).count()
  881. 1
  882. >>> db.system_js.add1(5)
  883. 6.0
  884. >>> del db.system_js.add1
  885. >>> db.system.js.find({"_id": "add1"}).count()
  886. 0
  887. """
  888. if not database.write_concern.acknowledged:
  889. database = database.client.get_database(
  890. database.name, write_concern=WriteConcern())
  891. # can't just assign it since we've overridden __setattr__
  892. object.__setattr__(self, "_db", database)
  893. def __setattr__(self, name, code):
  894. self._db.system.js.replace_one(
  895. {"_id": name}, {"_id": name, "value": Code(code)}, True)
  896. def __setitem__(self, name, code):
  897. self.__setattr__(name, code)
  898. def __delattr__(self, name):
  899. self._db.system.js.delete_one({"_id": name})
  900. def __delitem__(self, name):
  901. self.__delattr__(name)
  902. def __getattr__(self, name):
  903. return lambda *args: self._db.eval(Code("function() { "
  904. "return this[name].apply("
  905. "this, arguments); }",
  906. scope={'name': name}), *args)
  907. def __getitem__(self, name):
  908. return self.__getattr__(name)
  909. def list(self):
  910. """Get a list of the names of the functions stored in this database."""
  911. return [x["_id"] for x in self._db.system.js.find(projection=["_id"])]