Requests ======== PyMongo supports the idea of a *request*: a series of operations executed with a single socket, which are guaranteed to be processed on the server in the same order as they ran on the client. Requests are not usually necessary with PyMongo. By default, the methods :meth:`~pymongo.collection.Collection.insert`, :meth:`~pymongo.collection.Collection.update`, :meth:`~pymongo.collection.Collection.save`, and :meth:`~pymongo.collection.Collection.remove` block until they receive acknowledgment from the server, so ordered execution is already guaranteed. You can be certain the next :meth:`~pymongo.collection.Collection.find` or :meth:`~pymongo.collection.Collection.count`, for example, is executed on the server after the writes complete. This is called "read-your-writes consistency." An example of when a request is necessary is if a series of documents are inserted with ``w=0`` for performance reasons, and you want to query those documents immediately afterward: With ``w=0`` the writes can queue up at the server and might not be immediately visible in query results. Wrapping the inserts and queries within :meth:`~pymongo.mongo_client.MongoClient.start_request` and :meth:`~pymongo.mongo_client.MongoClient.end_request` forces a query to be on the same socket as the inserts, so the query won't execute until the inserts are complete on the server side. Example ------- Let's consider a collection of web-analytics counters. We want to count the number of page views our site has served for each combination of browser, region, and OS, and then show the user the number of page views from his or her region, *including* the user's own visit. We have three ways to do so reliably: 1. Simply update the counters with an acknowledged write (the default), and then ``find`` all counters for the visitor's region. This will ensure that the ``update`` completes before the ``find`` begins, but it comes with a performance penalty that may be unacceptable for analytics. 2. Create the :class:`~pymongo.mongo_client.MongoClient` with ``w=0`` and ``auto_start_request=True`` to do unacknowledged writes and ensure each thread gets its own socket. 3. Explicitly call :meth:`~pymongo.mongo_client.MongoClient.start_request`, then do the unacknowledged updates and the queries within the request. This third method looks like: .. testsetup:: from pymongo import MongoClient client = MongoClient() counts = client.requests_example.counts counts.drop() region, browser, os = 'US', 'Firefox', 'Mac OS X' .. doctest:: >>> client = MongoClient() >>> counts = client.requests_example.counts >>> region, browser, os = 'US', 'Firefox', 'Mac OS X' >>> request = client.start_request() >>> try: ... counts.update( ... {'region': region, 'browser': browser, 'os': os}, ... {'$inc': {'n': 1 }}, ... upsert=True, ... w=0) # unacknowledged write ... ... # This always runs after update has completed: ... count = sum([p['n'] for p in counts.find({'region': region})]) ... finally: ... request.end() >>> print count 1 Requests can also be used as context managers, with the `with statement <http://docs.python.org/reference/compound_stmts.html#index-15>`_, which makes the previous example more terse: .. doctest:: >>> client.in_request() False >>> with client.start_request(): ... # MongoClient is now in request ... counts.update( ... {'region': region, 'browser': browser, 'os': os}, ... {'$inc': {'n': 1 }}, ... upsert=True, ... safe=False) ... print sum([p['n'] for p in counts.find({'region': region})]) 2 >>> client.in_request() # request automatically ended False