def map_reduce(self, map, reduce, full_response=False, **kwargs): """Perform a map/reduce operation on this collection. If `full_response` is ``False`` (default) returns a :class:`~pymongo.collection.Collection` instance containing the results of the operation. Otherwise, returns the full response from the server to the `map reduce command`_. :Parameters: - `map`: map function (as a JavaScript string) - `reduce`: reduce function (as a JavaScript string) - `full_response` (optional): if ``True``, return full response to this command - otherwise just return the result collection - `**kwargs` (optional): additional arguments to the `map reduce command`_ may be passed as keyword arguments to this helper method, e.g.:: >>> db.test.map_reduce(map, reduce, limit=2) .. note:: Requires server version **>= 1.1.1** .. seealso:: :doc:`/examples/map_reduce` .. versionadded:: 1.1.2+ .. _map reduce command: http://www.mongodb.org/display/DOCS/MapReduce """ command = SON([("mapreduce", self.__collection_name), ("map", map), ("reduce", reduce)]) command.update(**kwargs) response = self.__database._command(command) if full_response: return response return self.__database[response["result"]]
def find_one(self, spec_or_object_id=None, fields=None, slave_okay=None, _sock=None, _must_use_master=False): """Get a single object from the database. Raises TypeError if the argument is of an improper type. Returns a single SON object, or None if no result is found. :Parameters: - `spec_or_object_id` (optional): a SON object specifying elements which must be present for a document to be returned OR an instance of ObjectId to be used as the value for an _id query - `fields` (optional): a list of field names that should be included in the returned document ("_id" will always be included) - `slave_okay` (optional): DEPRECATED this option is deprecated and will be removed - see the slave_okay parameter to `pymongo.Connection.__init__`. """ spec = spec_or_object_id if spec is None: spec = SON() if isinstance(spec, ObjectId): spec = SON({"_id": spec}) for result in self.find(spec, limit=-1, fields=fields, slave_okay=slave_okay, _sock=_sock, _must_use_master=_must_use_master): return result return None
def map_reduce(self, map, reduce, full_response=False, **kwargs): """Perform a map/reduce operation on this collection. If `full_response` is ``False`` (default) returns a :class:`~pymongo.collection.Collection` instance containing the results of the operation. Otherwise, returns the full response from the server to the `map reduce command`_. :Parameters: - `map`: map function (as a JavaScript string) - `reduce`: reduce function (as a JavaScript string) - `full_response` (optional): if ``True``, return full response to this command - otherwise just return the result collection - `**kwargs` (optional): additional arguments to the `map reduce command`_ may be passed as keyword arguments to this helper method, e.g.:: >>> db.test.map_reduce(map, reduce, limit=2) .. note:: Requires server version **>= 1.1.1** .. seealso:: :doc:`/examples/map_reduce` .. versionadded:: 1.2 .. _map reduce command: http://www.mongodb.org/display/DOCS/MapReduce """ command = SON([("mapreduce", self.__name), ("map", map), ("reduce", reduce)]) command.update(**kwargs) response = self.__database.command(command) if full_response: return response return self.__database[response["result"]]
def transform_incoming(self, son, collection): """Move _id to the front if it's there. """ if not "_id" in son: return son transformed = SON({"_id": son["_id"]}) transformed.update(son) return transformed
def __create(self, options): """Sends a create command with the given options. """ # Send size as a float, not an int/long. BSON can only handle 32-bit # ints which conflicts w/ max collection size of 10000000000. if "size" in options: options["size"] = float(options["size"]) command = SON({"create": self.__collection_name}) command.update(options) self.__database._command(command)
def authenticate(self, name, password): """Authenticate to use this database. Once authenticated, the user has full read and write access to this database. Raises TypeError if either name or password is not an instance of (str, unicode). Authentication lasts for the life of the database connection, or until `Database.logout` is called. The "admin" database is special. Authenticating on "admin" gives access to *all* databases. Effectively, "admin" access means root access to the database. :Parameters: - `name`: the name of the user to authenticate - `password`: the password of the user to authenticate """ if not isinstance(name, types.StringTypes): raise TypeError("name must be an instance of (str, unicode)") if not isinstance(password, types.StringTypes): raise TypeError("password must be an instance of (str, unicode)") result = self._command({"getnonce": 1}) nonce = result["nonce"] digest = self._password_digest(name, password) md5hash = _md5func() md5hash.update("%s%s%s" % (nonce, unicode(name), digest)) key = unicode(md5hash.hexdigest()) try: result = self._command( SON([("authenticate", 1), ("user", unicode(name)), ("nonce", nonce), ("key", key)])) return True except OperationFailure: return False
def rename(self, new_name): """Rename this collection. If operating in auth mode, client must be authorized as an admin to perform this operation. Raises TypeError if new_name is not an instance of (str, unicode). Raises InvalidName if new_name is not a valid collection name. :Parameters: - `new_name`: new name for this collection """ if not isinstance(new_name, types.StringTypes): raise TypeError("new_name must be an instance of (str, unicode)") if not new_name or ".." in new_name: raise InvalidName("collection names cannot be empty") if "$" in new_name: raise InvalidName("collection names must not contain '$'") if new_name[0] == "." or new_name[-1] == ".": raise InvalidName("collecion names must not start or end with '.'") rename_command = SON([("renameCollection", self.full_name()), ("to", "%s.%s" % (self.__database.name(), new_name))]) self.__database.connection().admin._command(rename_command)
def count(self, with_limit_and_skip=False): """Get the size of the results set for this query. Returns the number of documents in the results set for this query. Does not take :meth:`limit` and :meth:`skip` into account by default - set `with_limit_and_skip` to ``True`` if that is the desired behavior. Raises :class:`~pymongo.errors.OperationFailure` on a database error. :Parameters: - `with_limit_and_skip` (optional): take any :meth:`limit` or :meth:`skip` that has been applied to this cursor into account when getting the count .. note:: The `with_limit_and_skip` parameter requires server version **>= 1.1.4-** .. versionadded:: 1.1.1 The `with_limit_and_skip` parameter. :meth:`~pymongo.cursor.Cursor.__len__` was deprecated in favor of calling :meth:`count` with `with_limit_and_skip` set to ``True``. """ command = SON([("count", self.__collection.name()), ("query", self.__spec), ("fields", self.__fields)]) if with_limit_and_skip: if self.__limit: command["limit"] = self.__limit if self.__skip: command["skip"] = self.__skip response = self.__collection.database()._command( command, ["ns missing"]) if response.get("errmsg", "") == "ns missing": return 0 return int(response["n"])
def distinct(self, key): """Get a list of distinct values for `key` among all documents in the result set of this query. Raises :class:`TypeError` if `key` is not an instance of ``(str, unicode)``. :Parameters: - `key`: name of key for which we want to get the distinct values .. note:: Requires server version **>= 1.1.3+** .. seealso:: :meth:`pymongo.collection.Collection.distinct` .. versionadded:: 1.1.2+ """ if not isinstance(key, types.StringTypes): raise TypeError("key must be an instance of (str, unicode)") command = SON([("distinct", self.__collection.name()), ("key", key)]) if self.__spec: command["query"] = self.__spec return self.__collection.database()._command(command)["values"]
def drop_index(self, index_or_name): """Drops the specified index on this collection. Can be used on non-existant collections or collections with no indexes. Raises OperationFailure on an error. `index_or_name` can be either an index name (as returned by `create_index`), or an index specifier (as passed to `create_index`). An index specifier should be a list of (key, direction) pairs. Raises TypeError if index is not an instance of (str, unicode, list). :Parameters: - `index_or_name`: index (or name of index) to drop """ name = index_or_name if isinstance(index_or_name, types.ListType): name = self._gen_index_name(index_or_name) if not isinstance(name, types.StringTypes): raise TypeError("index_or_name must be an index name or list") self.database().connection()._purge_index(self.database().name(), self.name(), name) self.__database._command( SON([("deleteIndexes", self.__collection_name), ("index", name)]), ["ns not found"])
def transform_value(value): if isinstance(value, DBRef): return self.__database.dereference(value) elif isinstance(value, types.ListType): return [transform_value(v) for v in value] elif isinstance(value, types.DictType): return transform_dict(SON(value)) return value
def transform_value(value): if isinstance(value, types.DictType): if "_id" in value and "_ns" in value: return DBRef(value["_ns"], transform_value(value["_id"])) else: return transform_dict(SON(value)) elif isinstance(value, types.ListType): return [transform_value(v) for v in value] return value
def transform_outgoing(self, son, collection): """Manipulate an outgoing SON object. :Parameters: - `son`: the SON object being retrieved from the database - `collection`: the collection this object was stored in """ if self.will_copy(): return SON(son) return son
def transform_incoming(self, son, collection): """Manipulate an incoming SON object. :Parameters: - `son`: the SON object to be inserted into the database - `collection`: the collection the object is being inserted into """ if self.will_copy(): return SON(son) return son
def as_doc(self): """Get the SON document representation of this DBRef. Generally not needed by application developers """ doc = SON([("$ref", self.collection), ("$id", self.id)]) if self.database is not None: doc["$db"] = self.database return doc
def __query_spec(self): """Get the spec to use for a query. """ spec = SON({"query": self.__spec}) if self.__ordering: spec["orderby"] = self.__ordering if self.__explain: spec["$explain"] = True if self.__hint: spec["$hint"] = self.__hint if self.__snapshot: spec["$snapshot"] = True return spec
def count(self): """Get the size of the results set for this query. Returns the number of objects in the results set for this query. Does not take limit and skip into account. Raises OperationFailure on a database error. """ command = SON([("count", self.__collection.name()), ("query", self.__spec), ("fields", self.__fields)]) response = self.__collection.database()._command( command, ["ns missing"]) if response.get("errmsg", "") == "ns missing": return 0 return int(response["n"])
def find_one(self, spec_or_object_id=None, fields=None, slave_okay=None, _sock=None, _must_use_master=False): """Get a single object from the database. Raises TypeError if the argument is of an improper type. Returns a single SON object, or None if no result is found. :Parameters: - `spec_or_object_id` (optional): a SON object specifying elements which must be present for a document to be returned OR an instance of ObjectId to be used as the value for an _id query - `fields` (optional): a list of field names that should be included in the returned document ("_id" will always be included) - `slave_okay` (optional): if True, this query should be allowed to execute on a slave (by default, certain queries are not allowed to execute on mongod instances running in slave mode). If slave_okay is set to None the Connection level default will be used - see the slave_okay parameter to `pymongo.Connection.__init__`. """ spec = spec_or_object_id if spec is None: spec = SON() if isinstance(spec, ObjectId): spec = SON({"_id": spec}) for result in self.find(spec, limit=-1, fields=fields, slave_okay=slave_okay, _sock=_sock, _must_use_master=_must_use_master): return result return None
def transform_outgoing(self, son, collection): """Replace DBRefs with embedded documents. """ def transform_value(value): if isinstance(value, DBRef): return self.__database.dereference(value) elif isinstance(value, types.ListType): return [transform_value(v) for v in value] elif isinstance(value, types.DictType): return transform_dict(SON(value)) return value def transform_dict(object): for (key, value) in object.items(): object[key] = transform_value(value) return object return transform_dict(SON(son))
def create_index(self, key_or_list, direction=None, unique=False, ttl=300): """Creates an index on this collection. Takes either a single key or a list of (key, direction) pairs. The key(s) must be an instance of ``(str, unicode)``, and the directions must be one of (:data:`~pymongo.ASCENDING`, :data:`~pymongo.DESCENDING`). Returns the name of the created index. :Parameters: - `key_or_list`: a single key or a list of (key, direction) pairs specifying the index to create - `direction` (optional): DEPRECATED this option will be removed - `unique` (optional): should this index guarantee uniqueness? - `ttl` (optional): time window (in seconds) during which this index will be recognized by subsequent calls to :meth:`ensure_index` - see documentation for :meth:`ensure_index` for details """ if not isinstance(key_or_list, (str, unicode, list)): raise TypeError( "key_or_list must either be a single key or a list of (key, direction) pairs" ) if direction is not None: warnings.warn( "specifying a direction for a single key index is " "deprecated and will be removed. there is no need " "for a direction on a single key index", DeprecationWarning) to_save = SON() keys = helpers._index_list(key_or_list) name = self._gen_index_name(keys) to_save["name"] = name to_save["ns"] = self.full_name() to_save["key"] = helpers._index_document(keys) to_save["unique"] = unique self.database().connection()._cache_index(self.__database.name(), self.name(), name, ttl) self.database().system.indexes.insert(to_save, manipulate=False, check_keys=False) return to_save["name"]
def transform_incoming(self, son, collection): """Replace embedded documents with DBRefs. """ def transform_value(value): if isinstance(value, types.DictType): if "_id" in value and "_ns" in value: return DBRef(value["_ns"], transform_value(value["_id"])) else: return transform_dict(SON(value)) elif isinstance(value, types.ListType): return [transform_value(v) for v in value] return value def transform_dict(object): for (key, value) in object.items(): object[key] = transform_value(value) return object return transform_dict(SON(son))
def __query_spec(self): """Get the spec to use for a query. Just `self.__spec`, unless this cursor needs special query fields, like orderby. """ if not self.__ordering and not self.__explain and not self.__hint: return self.__spec spec = SON({"query": self.__spec}) if self.__ordering: spec["orderby"] = self.__ordering if self.__explain: spec["$explain"] = True if self.__hint: spec["$hint"] = self.__hint if self.__snapshot: spec["$snapshot"] = True return spec
def remove(self, spec_or_object_id): """Remove an object(s) from this collection. Raises TypeEror if the argument is not an instance of (dict, ObjectId). :Parameters: - `spec_or_object_id` (optional): a SON object specifying elements which must be present for a document to be removed OR an instance of ObjectId to be used as the value for an _id element """ spec = spec_or_object_id if isinstance(spec, ObjectId): spec = SON({"_id": spec}) if not isinstance(spec, types.DictType): raise TypeError("spec must be an instance of dict, not %s" % type(spec)) self._send_message(2006, _ZERO + bson.BSON.from_dict(spec))
def _index_document(index_list): """Helper to generate an index specifying document. Takes a list of (key, direction) pairs. """ if not isinstance(index_list, list): raise TypeError("if no direction is specified, key_or_list must be an " "instance of list") if not len(index_list): raise ValueError("key_or_list must not be the empty list") index = SON() for (key, value) in index_list: if not isinstance(key, (str, unicode)): raise TypeError("first item in each key pair must be a string") if not isinstance(value, int): raise TypeError( "second item in each key pair must be ASCENDING or " "DESCENDING") index[key] = value return index
def eval(self, code, *args): """Evaluate a JavaScript expression on the Mongo server. Useful if you need to touch a lot of data lightly; in such a scenario the network transfer of the data could be a bottleneck. The `code` argument must be a JavaScript function. Additional positional arguments will be passed to that function when it is run on the server. Raises TypeError if `code` is not an instance of (str, unicode, `Code`). Raises OperationFailure if the eval fails. Returns the result of the evaluation. :Parameters: - `code`: string representation of JavaScript code to be evaluated - `args` (optional): additional positional arguments are passed to the `code` being evaluated """ if not isinstance(code, Code): code = Code(code) command = SON([("$eval", code), ("args", list(args))]) result = self._command(command) return result.get("retval", None)
def _element_to_bson(key, value, check_keys): if not isinstance(key, (str, unicode)): raise InvalidDocument( "documents must have only string keys, key was %r" % key) if check_keys: if key.startswith("$"): raise InvalidName("key %r must not start with '$'" % key) if "." in key: raise InvalidName("key %r must not contain '.'" % key) name = _make_c_string(key) if isinstance(value, float): return "\x01" + name + struct.pack("<d", value) # Use Binary w/ subtype 3 for UUID instances try: import uuid if isinstance(value, uuid.UUID): value = Binary(value.bytes, subtype=3) except ImportError: pass if isinstance(value, Binary): subtype = value.subtype if subtype == 2: value = struct.pack("<i", len(value)) + value return "\x05%s%s%s%s" % (name, struct.pack( "<i", len(value)), chr(subtype), value) if isinstance(value, Code): cstring = _make_c_string(value) scope = _dict_to_bson(value.scope, False) full_length = struct.pack("<i", 8 + len(cstring) + len(scope)) length = struct.pack("<i", len(cstring)) return "\x0F" + name + full_length + length + cstring + scope if isinstance(value, str): cstring = _make_c_string(value) length = struct.pack("<i", len(cstring)) return "\x02" + name + length + cstring if isinstance(value, unicode): cstring = _make_c_string(value) length = struct.pack("<i", len(cstring)) return "\x02" + name + length + cstring if isinstance(value, dict): return "\x03" + name + _dict_to_bson(value, check_keys) if isinstance(value, (list, tuple)): as_dict = SON(zip([str(i) for i in range(len(value))], value)) return "\x04" + name + _dict_to_bson(as_dict, check_keys) if isinstance(value, ObjectId): return "\x07" + name + value.binary if value is True: return "\x08" + name + "\x01" if value is False: return "\x08" + name + "\x00" if isinstance(value, (int, long)): # TODO this is a really ugly way to check for this... if value > 2**64 / 2 - 1 or value < -2**64 / 2: raise OverflowError("MongoDB can only handle up to 8-byte ints") if value > 2**32 / 2 - 1 or value < -2**32 / 2: return "\x12" + name + struct.pack("<q", value) return "\x10" + name + struct.pack("<i", value) if isinstance(value, datetime.datetime): millis = int( calendar.timegm(value.timetuple()) * 1000 + value.microsecond / 1000) return "\x09" + name + struct.pack("<q", millis) if value is None: return "\x0A" + name if isinstance(value, _RE_TYPE): pattern = value.pattern flags = "" if value.flags & re.IGNORECASE: flags += "i" if value.flags & re.LOCALE: flags += "l" if value.flags & re.MULTILINE: flags += "m" if value.flags & re.DOTALL: flags += "s" if value.flags & re.UNICODE: flags += "u" if value.flags & re.VERBOSE: flags += "x" return "\x0B" + name + _make_c_string(pattern) + _make_c_string(flags) if isinstance(value, DBRef): return _element_to_bson(key, value.as_doc(), False) raise InvalidDocument("cannot convert value of type %s to bson" % type(value))
def find(self, spec=None, fields=None, skip=0, limit=0, slave_okay=None, timeout=True, snapshot=False, _sock=None, _must_use_master=False): """Query the database. The `spec` argument is a prototype document that all results must match. For example: >>> db.test.find({"hello": "world"}) only matches documents that have a key "hello" with value "world". Matches can have other keys *in addition* to "hello". The `fields` argument is used to specify a subset of fields that should be included in the result documents. By limiting results to a certain subset of fields you can cut down on network traffic and decoding time. Raises TypeError if any of the arguments are of improper type. Returns an instance of Cursor corresponding to this query. :Parameters: - `spec` (optional): a SON object specifying elements which must be present for a document to be included in the result set - `fields` (optional): a list of field names that should be returned in the result set ("_id" will always be included) - `skip` (optional): the number of documents to omit (from the start of the result set) when returning the results - `limit` (optional): the maximum number of results to return - `slave_okay` (optional): if True, this query should be allowed to execute on a slave (by default, certain queries are not allowed to execute on mongod instances running in slave mode). If slave_okay is set to None the Connection level default will be used - see the slave_okay parameter to `pymongo.Connection.__init__`. - `timeout` (optional): if True, any returned cursor will be subject to the normal timeout behavior of the mongod process. Otherwise, the returned cursor will never timeout at the server. Care should be taken to ensure that cursors with timeout turned off are properly closed. - `snapshot` (optional): if True, snapshot mode will be used for this query. Snapshot mode assures no duplicates are returned, or objects missed, which were present at both the start and end of the query's execution. For details, see the wiki_ .. _wiki: http://www.mongodb.org/display/DOCS/How+to+do+Snapshotting+in+the+Mongo+Database """ if spec is None: spec = SON() if slave_okay is None: slave_okay = self.__database.connection().slave_okay if not isinstance(spec, types.DictType): raise TypeError("spec must be an instance of dict") if not isinstance(fields, (types.ListType, types.NoneType)): raise TypeError("fields must be an instance of list") if not isinstance(skip, types.IntType): raise TypeError("skip must be an instance of int") if not isinstance(limit, types.IntType): raise TypeError("limit must be an instance of int") if not isinstance(slave_okay, types.BooleanType): raise TypeError("slave_okay must be an instance of bool") if not isinstance(timeout, types.BooleanType): raise TypeError("timeout must be an instance of bool") if not isinstance(snapshot, types.BooleanType): raise TypeError("snapshot must be an instance of bool") if fields is not None: if not fields: fields = ["_id"] fields = self._fields_list_to_dict(fields) return Cursor(self, spec, fields, skip, limit, slave_okay, timeout, snapshot, _sock=_sock, _must_use_master=_must_use_master)