Example #1
0
    def _copy_only_fields(self, doc, fields):
        """Copy only the specified fields."""

        if fields is None:
            return copy.deepcopy(doc)
        else:
            if not fields:
                fields = {"_id": 1}
            if not isinstance(fields, dict):
                fields = helpers._fields_list_to_dict(fields)

            #we can pass in something like {"_id":0, "field":1}, so pull the id value out and hang on to it until later
            id_value = fields.pop('_id', 1)

            #other than the _id field, all fields must be either includes or excludes, this can evaluate to 0
            if len(set(list(fields.values()))) > 1:
                raise ValueError('You cannot currently mix including and excluding fields.')
            
            #if we have novalues passed in, make a doc_copy based on the id_value
            if len(list(fields.values())) == 0:
                if id_value == 1:
                    doc_copy = {}
                else:
                    doc_copy = copy.deepcopy(doc)
            #if 1 was passed in as the field values, include those fields
            elif  list(fields.values())[0] == 1:
                doc_copy = {}
                for key in fields:
                    if key in doc:
                        doc_copy[key] = doc[key]
            #otherwise, exclude the fields passed in
            else:
                doc_copy = copy.deepcopy(doc)
                for key in fields:
                    if key in doc_copy:
                        del doc_copy[key]

            #set the _id value if we requested it, otherwise remove it
            if id_value == 0:
                if '_id' in doc_copy:
                    del doc_copy['_id']
            else:
                if '_id' in doc:
                    doc_copy['_id'] = doc['_id']

            fields['_id'] = id_value #put _id back in fields
            return doc_copy
Example #2
0
 def find(self, spec=None, fields=None, skip=0, limit=0,
              timeout=True, snapshot=False, tailable=False, sort=None,
              max_scan=None,
              _must_use_master=False, _is_command=False,
              callback=None):
     """Query the database.
     
     The `spec` argument is a prototype document that all results
     must match. For example:
     
     >>> db.test.find({"hello": "world"}, callback=...)
     
     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 :class:`TypeError` if any of the arguments are of
     improper type.
     
     :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), or a dict specifying the fields to return
       - `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
       - `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 `snapshot documentation
         <http://dochub.mongodb.org/core/snapshot>`_.
       - `tailable` (optional): the result of this find call will
         be a tailable cursor - tailable cursors aren't closed when
         the last data is retrieved but are kept open and the
         cursors location marks the final document's position. if
         more data is received iteration of the cursor will
         continue from the last document received. For details, see
         the `tailable cursor documentation
         <http://www.mongodb.org/display/DOCS/Tailable+Cursors>`_.
       - `sort` (optional): a list of (key, direction) pairs
         specifying the sort order for this query. See
         :meth:`~pymongo.cursor.Cursor.sort` for details.
       - `max_scan` (optional): limit the number of documents
         examined when performing the query
     
     .. mongodoc:: find
     """
     
     if spec is None:
         spec = {}
     
     if not isinstance(spec, dict):
         raise TypeError("spec must be an instance of dict")
     if not isinstance(skip, int):
         raise TypeError("skip must be an instance of int")
     if not isinstance(limit, int):
         raise TypeError("limit must be an instance of int")
     if not isinstance(timeout, bool):
         raise TypeError("timeout must be an instance of bool")
     if not isinstance(snapshot, bool):
         raise TypeError("snapshot must be an instance of bool")
     if not isinstance(tailable, bool):
         raise TypeError("tailable must be an instance of bool")
     if not callable(callback):
         raise TypeError("callback must be callable")
     
     if fields is not None:
         if not fields:
             fields = {"_id": 1}
         if not isinstance(fields, dict):
             fields = helpers._fields_list_to_dict(fields)
     
     self.__spec = spec
     self.__fields = fields
     self.__skip = skip
     self.__limit = limit
     self.__batch_size = 0
     
     self.__timeout = timeout
     self.__tailable = tailable
     self.__snapshot = snapshot
     self.__ordering = sort and helpers._index_document(sort) or None
     self.__max_scan = max_scan
     self.__explain = False
     self.__hint = None
     # self.__as_class = as_class
     self.__tz_aware = False #collection.database.connection.tz_aware
     self.__must_use_master = _must_use_master
     self.__is_command = _is_command
     
     connection = self.__pool.connection()
     try:
         connection.send_message(
             message.query(self.__query_options(),
                           self.full_collection_name,
                           self.__skip, 
                           self.__limit,
                           self.__query_spec(),
                           self.__fields), 
             callback=functools.partial(self._handle_response, orig_callback=callback))
     except Exception as e:
         connection.close()
Example #3
0
 def find(self, spec=None, fields=None, skip=0, limit=0,
              timeout=True, snapshot=False, tailable=False, sort=None,
              max_scan=None, slave_okay=False,
              _must_use_master=False, _is_command=False,
              callback=None):
     """Query the database.
     
     The `spec` argument is a prototype document that all results
     must match. For example:
     
     >>> db.test.find({"hello": "world"}, callback=...)
     
     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 :class:`TypeError` if any of the arguments are of
     improper type.
     
     :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), or a dict specifying the fields to return
       - `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
       - `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 `snapshot documentation
         <http://dochub.mongodb.org/core/snapshot>`_.
       - `tailable` (optional): the result of this find call will
         be a tailable cursor - tailable cursors aren't closed when
         the last data is retrieved but are kept open and the
         cursors location marks the final document's position. if
         more data is received iteration of the cursor will
         continue from the last document received. For details, see
         the `tailable cursor documentation
         <http://www.mongodb.org/display/DOCS/Tailable+Cursors>`_.
       - `sort` (optional): a list of (key, direction) pairs
         specifying the sort order for this query. See
         :meth:`~pymongo.cursor.Cursor.sort` for details.
       - `max_scan` (optional): limit the number of documents
         examined when performing the query
       - `slave_okay` (optional): is it okay to connect directly
         to and perform queries on a slave instance
     
     .. mongodoc:: find
     """
     
     if spec is None:
         spec = {}
     
     if not isinstance(spec, dict):
         raise TypeError("spec must be an instance of dict")
     if not isinstance(skip, int):
         raise TypeError("skip must be an instance of int")
     if not isinstance(limit, int):
         raise TypeError("limit must be an instance of int")
     if not isinstance(timeout, bool):
         raise TypeError("timeout must be an instance of bool")
     if not isinstance(snapshot, bool):
         raise TypeError("snapshot must be an instance of bool")
     if not isinstance(tailable, bool):
         raise TypeError("tailable must be an instance of bool")
     if not callable(callback):
         raise TypeError("callback must be callable")
     
     if fields is not None:
         if not fields:
             fields = {"_id": 1}
         if not isinstance(fields, dict):
             fields = helpers._fields_list_to_dict(fields)
     
     self.__spec = spec
     self.__fields = fields
     self.__skip = skip
     self.__limit = limit
     self.__batch_size = 0
     
     self.__timeout = timeout
     self.__tailable = tailable
     self.__snapshot = snapshot
     self.__ordering = sort and helpers._index_document(sort) or None
     self.__max_scan = max_scan
     self.__slave_okay = slave_okay
     self.__explain = False
     self.__hint = None
     # self.__as_class = as_class
     self.__tz_aware = False #collection.database.connection.tz_aware
     self.__must_use_master = _must_use_master
     self.__is_command = _is_command
     
     connection = self.__pool.connection()
     try:
         connection.send_message(
             message.query(self.__query_options(),
                           self.full_collection_name,
                           self.__skip, 
                           self.__limit,
                           self.__query_spec(),
                           self.__fields), 
             callback=functools.partial(self._handle_response, orig_callback=callback))
     except Exception, e:
         logging.error('Error sending query %s' % e)
         connection.close()
         raise
Example #4
0
    def find(self, spec=None, fields=None, skip=0, limit=0,
                 timeout=True, snapshot=False, tailable=False, sort=None,
                 max_scan=None, slave_okay=False,
                 await_data=False,
                 _must_use_master=False, _is_command=False,
                 callback=None, batch_size=0):
        """Query the database.

        The `spec` argument is a prototype document that all results
        must match. For example:

        >>> db.test.find({"hello": "world"}, callback=...)

        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 :class:`TypeError` if any of the arguments are of
        improper type.

        Returns a cursor. find() calls your callback either with an error,
        or with the first 100 documents. You must call get_more() repeatedly
        on the cursor until it is exhausted:

        class Handler(tornado.web.RequestHandler):
          @tornado.web.asynchronous
          def get(self):
            self.cursor = self.db.collection.find({}, batch_size=300,
              callback=self._on_response
            )

          def _on_response(self, response, error):
            assert not error
            self.write(str(response))
            if self.cursor.alive:
              self.cursor.get_more(self._on_response)
            else:
              self.finish()

        :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), or a dict specifying the fields to return
          - `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
          - `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 `snapshot documentation
            <http://dochub.mongodb.org/core/snapshot>`_.
          - `tailable` (optional): the result of this find call will
            be a tailable cursor - tailable cursors aren't closed when
            the last data is retrieved but are kept open and the
            cursors location marks the final document's position. if
            more data is received iteration of the cursor will
            continue from the last document received. For details, see
            the `tailable cursor documentation
            <http://www.mongodb.org/display/DOCS/Tailable+Cursors>`_.
            .. versionadded:: 1.2
          - `sort` (optional): a list of (key, direction) pairs
            specifying the sort order for this query. See
            :meth:`~pymongo.cursor.Cursor.sort` for details.
          - `max_scan` (optional): limit the number of documents
            examined when performing the query
          - `slave_okay` (optional): is it okay to connect directly
            to and perform queries on a slave instance
          - `await_data` (optional): if True, the server will block for
            some extra time before returning, waiting for more data to
            return. Ignored if `tailable` is False.
            .. versionadded:: 1.2
          - `callback` (optional): a function that takes arguments (result,
            error): a list of result documents, or an Exception
          - `batch_size`: The size of each batch of results requested.
            .. versionadded:: 1.2

        .. mongodoc:: find
        """

        if self.__id and self.alive:
            logging.warn("Do not call find() twice on the same collection object")

        if spec is None:
            spec = {}
        
        if limit is None:
            limit = 0

        if not isinstance(spec, dict):
            raise TypeError("spec must be an instance of dict")
        if not isinstance(skip, int):
            raise TypeError("skip must be an instance of int")
        if not isinstance(limit, int):
            raise TypeError("limit must be an instance of int or None")
        if not isinstance(timeout, bool):
            raise TypeError("timeout must be an instance of bool")
        if not isinstance(snapshot, bool):
            raise TypeError("snapshot must be an instance of bool")
        if not isinstance(tailable, bool):
            raise TypeError("tailable must be an instance of bool")
        if not isinstance(await_data, bool):
            raise TypeError("await_data must be an instance of bool")
        if not callable(callback):
            raise TypeError("callback must be callable")

        if fields is not None:
            if not fields:
                fields = {"_id": 1}
            if not isinstance(fields, dict):
                fields = helpers._fields_list_to_dict(fields)

        self.__spec = spec
        self.__fields = fields
        self.__skip = skip
        self.__limit = limit
        self.__batch_size = batch_size

        self.__timeout = timeout
        self.__tailable = tailable
        self.__await_data = tailable and await_data
        self.__snapshot = snapshot
        self.__ordering = sort and helpers._index_document(sort) or None
        self.__max_scan = max_scan
        self.__slave_okay = slave_okay
        self.__explain = False
        self.__hint = None
        # self.__debug = debug
        # self.__as_class = as_class
        self.__tz_aware = False #collection.database.connection.tz_aware
        self.__must_use_master = _must_use_master
        self.__is_command = _is_command
        self.__killed = False

        ntoreturn = self.__batch_size
        if self.__limit:
            if self.__batch_size:
                ntoreturn = min(self.__limit, self.__batch_size)
            else:
                ntoreturn = self.__limit

        def _handle_conn(connection):
            try:
                connection.send_message(
                    message.query(self.__query_options(),
                                  self.full_collection_name,
                                  self.__skip,
                                  ntoreturn,
                                  self.__query_spec(),
                                  self.__fields),
                    callback=functools.partial(self._handle_response, orig_callback=callback))
            except Exception, e:
                logging.error('Error sending query %s' % e)
                connection.close()
                raise