From 05ea42c6d45caf8a83f5aa267733456b107fa671 Mon Sep 17 00:00:00 2001 From: Mike Dirolf Date: Thu, 12 Nov 2009 10:56:21 -0500 Subject: [PATCH] tutorial --- doc/conf.py | 5 +- doc/index.rst | 27 +++++- doc/tutorial.rst | 219 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+), 3 deletions(-) create mode 100644 doc/tutorial.rst diff --git a/doc/conf.py b/doc/conf.py index be575f2f9..46f12cd05 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -13,7 +13,8 @@ import pymongo # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.coverage'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.coverage', + 'sphinx.ext.todo'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -61,9 +62,9 @@ pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] +# -- Options for extensions ---------------------------------------------------- autoclass_content = 'both' - # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with diff --git a/doc/index.rst b/doc/index.rst index b56e89af1..16706353c 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,11 +1,36 @@ PyMongo |release| Documentation =============================== -Contents: +About +----- +**PyMongo** is a Python distribution containing tools for working with +`MongoDB `_. + +About This Documentation +------------------------ +This documentation is generated using the `Sphinx +`_ documentation generator. The source files +for the documentation are located in the *doc/* directory of the +**PyMongo** distribution. To generate the docs locally do: + +.. code-block:: bash + + $ python setup.py doc + +In the root directory of the **PyMongo** source. + +Contributions (or fixes) to the documentation are highly encouraged! +To contribute, fork the project on `github +`_ and send a pull +request. + +Contents +-------- .. toctree:: :maxdepth: 3 + tutorial api/index Indices and tables diff --git a/doc/tutorial.rst b/doc/tutorial.rst new file mode 100644 index 000000000..de1eca9ad --- /dev/null +++ b/doc/tutorial.rst @@ -0,0 +1,219 @@ +Tutorial +======== +This tutorial is intended as an introduction to working with +**MongoDB** and **PyMongo**. + +Prerequisites +------------- +.. todo:: link to installation instructions + +Before we start, make sure that you have the **PyMongo** distribution +installed. In the Python shell, the following should run without +raising an exception:: + + >>> import pymongo + +This tutorial also assumes that a MongoDB instance is running on the +default host and port. Assuming you have `downloaded and installed +`_ MongoDB, you +can start it like so: + +.. code-block:: bash + + $ mongod + +Making a Connection +------------------- +The first step when working with **PyMongo** is to make a connection +to the running **mongod** instance. Doing so is easy:: + + >>> from pymongo import Connection + >>> connection = Connection() + +The above code will connect on the default host and port. We can also +specify the host and port explicitly, as follows:: + + >>> connection = Connection('localhost', 27017) + +Getting a Database +------------------ +A single instance of MongoDB can support multiple independent +`databases `_. When +working with PyMongo you access databases using attribute style access +to a Connection instance:: + + >>> db = connection.test_database + +If your database name is such that you attribute style access won't +work (like ``test-database``) you can use dictionary style access +instead:: + + >>> db = connection['test-database'] + +Getting a Collection +-------------------- +A `collection `_ is a +group of documents stored in MongoDB, and can be thought of as roughly +the equivalent of a table in a relational database. Getting a +collection in PyMongo works the same as getting a database:: + + >>> collection = db.test_collection + +or (using dictionary style access):: + + >>> collection = db['test-collection'] + +An important note about collections (and databases) in MongoDB is that +they are created lazily - none of the above commands have actually +performed any operations on the MongoDB server. Collections and +databases are created when the first document is inserted into them. + +Documents +--------- +Data in MongoDB is represented (and stored) using JSON-style +documents. In PyMongo we use dictionaries to represent documents. As +an example, the following dictionary might be used to represent a blog +post:: + + >>> post = {"author": "Mike", + ... "text": "My first blog post!", + ... "tags": ["mongodb", "python", "pymongo"], + ... "date": datetime.datetime.utcnow()} + +Note that documents can contain native Python types (like +:class:`datetime.datetime` instances) which will be automatically +converted to and from the appropriate `BSON +`_ types. + +.. todo:: link to table of Python <-> BSON types + +Inserting a Document +-------------------- +To insert a document into a collection we can use the +:meth:`~pymongo.collection.Collection.insert` method:: + + >>> posts = db.posts + >>> posts.insert(post) + ObjectId('4afc29d4e6fb1b16f2000000') + +When a document is inserted a special key, ``"_id"``, is automatically +added if the document doesn't already contain an ``"_id"`` key. The value +of ``"_id"`` must be unique across the +collection. :meth:`~pymongo.collection.Collection.insert` returns the +value of ``"_id"`` for the inserted document. For more information, see the +`documentation on _id +`_. + +.. todo:: notes on the differences between save and insert + +After inserting the first document, the *posts* collection has +actually been created on the server. We can verify this by listing all +of the collections in our database:: + + >>> db.collection_names() + [u'posts', u'system.indexes'] + +.. note:: The *system.indexes* collection is a special internal + collection that was created automatically. + + +Getting a Single Document With :meth:`~pymongo.collection.Collection.find_one` +------------------------------------------------------------------------------ +The most basic type of query that can be performed in MongoDB is +:meth:`~pymongo.collection.Collection.find_one`. This method returns a +single document matching a query (or ``None`` if there are no +matches). It is useful when you know there is only one matching +document, or are only interested in the first match. Here we use +:meth:`~pymongo.collection.Collection.find_one` to get the first +document from the posts collection:: + + >>> posts.find_one() + {u'date': datetime.datetime(2009, 11, 12, 15, 3, 3, 489000), u'text': u'My first blog post!', u'_id': ObjectId('4afc29d4e6fb1b16f2000000'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']} + +The result is a dictionary matching the one that we inserted previously. + +.. note:: The returned document contains an ``"_id"`` which was + automatically added on insert. + +:meth:`~pymongo.collection.Collection.find_one` also supports querying +on specific elements that the resulting document must match. To limit +our results to a document with author "Mike" we do:: + + >>> posts.find_one({"author": "Mike"}) + {u'date': datetime.datetime(2009, 11, 12, 15, 3, 3, 489000), u'text': u'My first blog post!', u'_id': ObjectId('4afc29d4e6fb1b16f2000000'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']} + +If we try with a different author, like "Eliot", we'll get no result:: + + >>> posts.find_one({"author": "Eliot"}) + +Bulk Inserts +------------ +In order to make querying a little more interesting, let's insert a +few more documents. In addition to inserting a single document, we can +also perform *bulk* insert operations, by passing an iterable as the +first argument to :meth:`~pymongo.collection.Collection.insert`. This +will insert each document in the iterable, sending only a single +command to the server:: + + >>> new_posts = [{"author": "Mike", + ... "text": "Another post!", + ... "tags": ["bulk", "insert"], + ... "date": datetime.datetime(2009, 11, 12, 11, 14)}, + ... {"author": "Eliot", + ... "title": "MongoDB is fun", + ... "text": "and pretty easy too!", + ... "date": datetime.datetime(2009, 11, 10, 10, 45)}] + >>> posts.insert(new_posts) + [ObjectId('4afc34dee6fb1b16f2000001'), ObjectId('4afc34dee6fb1b16f2000002')] + +There are a couple of interesting things to note about this example: + + - The call to :meth:`~pymongo.collection.Collection.insert` now + returns two :class:`~pymongo.objectid.ObjectId` instances, one for + each inserted document. + - ``new_posts[1]`` has a different "shape" than the other posts - + there is no ``"tags"`` field and we've added a new field, + ``"title"``. This is what we mean when we say that MongoDB is + *schema-free*. + +Querying for More Than One Document +----------------------------------- +To get more than a single document as the result of a query we use the +:meth:`~pymongo.collection.Collection.find` +method. :meth:`~pymongo.collection.Collection.find` returns a +:class:`~pymongo.cursor.Cursor` instance, which allows us to iterate +over all matching documents. For example, we can iterate over every +document in the ``posts`` collection:: + + >>> for post in posts.find(): + ... post + ... + {u'date': datetime.datetime(2009, 11, 12, 15, 3, 3, 489000), u'text': u'My first blog post!', u'_id': ObjectId('4afc29d4e6fb1b16f2000000'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']} + {u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('4afc34dee6fb1b16f2000001'), u'author': u'Mike', u'tags': [u'bulk', u'insert']} + {u'date': datetime.datetime(2009, 11, 10, 10, 45), u'text': u'and pretty easy too!', u'_id': ObjectId('4afc34dee6fb1b16f2000002'), u'author': u'Eliot', u'title': u'MongoDB is fun'} + +Just like we did with :meth:`~pymongo.collection.Collection.find_one`, +we can pass a document to :meth:`~pymongo.collection.Collection.find` +to limit the returned results. Here, we get only those documents whose +author is "Mike":: + + >>> for post in posts.find({"author": "Mike"}): + ... post + ... + {u'date': datetime.datetime(2009, 11, 12, 15, 3, 3, 489000), u'text': u'My first blog post!', u'_id': ObjectId('4afc29d4e6fb1b16f2000000'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']} + {u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('4afc34dee6fb1b16f2000001'), u'author': u'Mike', u'tags': [u'bulk', u'insert']} + +Counting +-------- +If we just want to know how many documents match a query we can +perform a :meth:`~pymongo.cursor.Cursor.count` operation instead of a +full query. We can get a count of all of the documents in a +collection:: + + >>> posts.count() + 3 + +or just of those posts that match a specific query:: + + >>> posts.find({"author": "Mike"}).count() + 2