.. _pymongo : http://api.mongodb.org/python/
.. _Connection : http://api.mongodb.org/python/current/tutorial.html#making-a-connection

=============================
Getting Started with MongoKit
=============================

MongoKit is based on pymongo_. As such, all of the pymongo API is exposed
through MongoKit. If you don't find what you want in the MongoKit API,
please take a look at pymongo's documentation. All the pymongo API is
exposed via connection, database and collection so Connection, Database and
Collection are wrappers around pymongo objects.

In this example, we will create a simple MongoKit document definition and use
it to create new instances of that document.

Defining a Document
-------------------

Start by defining the Document::

    from mongokit import Document, Connection
    import datetime

    class BlogPost(Document):
        structure = {
            'title': basestring,
            'body': basestring,
            'author': basestring,
            'date_creation': datetime.datetime,
            'rank': int,
            'tags': [basestring],
        }
        required_fields = ['title', 'author', 'date_creation']
        default_values = {
            'rank': 0,
            'date_creation': datetime.datetime.utcnow
        }

The ``structure`` is simply a dictionary with python type. In this example,
``title`` must be a string and ``rank`` must be an int. For more information,
see :doc:`structure`.

Optionally, you can add some descriptors. In order to specify fields which are
required, just add a ``required_fields`` attribute. This is a simple list which
list all required_fields (ie, those field must not be None when validating).
You can also specify the ``default_values`` attribute which can indicates the
default values of a Documents structure. Note that you can pass callable object (like a 
``datetime.utcnow``). For more information, see :doc:`descriptors`.

Connecting to MongoDB
---------------------

Now, to open a connection to MongoDB::

    connection = Connection()

This a wrapped version of pymongo's Connection_ and will attempt to connect to a MongoDB instance running locally.

e.g. Speficying a host

    connection = Connection(host="HOSTNAME", port=PORT)

e.g. Specifying a Replica Set host

    from mongokit import ReplicaSetConnection

    connection = ReplicaSetConnection(
        host="HOSTNAME:PORT,HOSTNAME:PORT"
        replicaset="REPLICA_SET_NAME",
        read_preferences=pymongo.read_preferences.ReadPreferance.SECONDARY_PREFERRED)

For more information on how to configure the Connection, see pymongo_'s documentation.

Once you have an active connection, you need to register your the ``BlogPost``
object::

    connection.register([BlogPost])

Alternatively, the register method can be used as a decorator::

    @connection.register
    class BlogPost(Document):
        structure = {...}

Now, let's create a new blogpost in the "blog_posts" collection in the database
"blog". In pymongo's syntax, you would use 
``connection.<database>.<collection>`` to access the collection. Once you have
the collection, you can create a new document::

    >>> connection.test.blogpost.BlogPost()
    {'body': None, 'title': None, 'author': None, 'rank': 0, 'date_creation': datetime.datetime(...), 'tags': []}

Note that ``date_creation`` was automatically filled by ``utcnow()`` and rank is ``0``.

To avoid repeating ourselves though, let's specify the database and collection
name in the Document definition::

    @connection.register
    class BlogPost(Document):
        __collection__ = 'blog_posts'
        __database__ = 'blog'
        structure = {...}

Now, we can have access to our document directly from the connection::

    >>> bp = connection.BlogPost()
    >>> bp
    {'body': None, 'title': None, 'author': None, 'rank': 0, 'date_creation': datetime.datetime(...), 'tags': []}

Modifying the Document
----------------------

Now let's modify our BlogPost and try the validation::

    >>> bp['title'] = 1
    >>> bp.validate() 
    Traceback (most recent call last):
    ...
    SchemaTypeError: title must be an instance of basestring not int

Alright, type validation works. :

    >>> bp['title'] = 'my first blog post'

``validate`` method will also check if all the required fields are set::

    >>> bp.validate()
    Traceback (most recent call last):
    ...
    RequireFieldError: author is required

    >>> bp['author'] = u'myself'
    >>> bp.validate()
    >>> 

Now let's save our new blogpost to the database::

    >>> bp.save()

Note that ``save`` will call the ``validate`` method, so you don't have to validate
each time.

Querying the Database
---------------------

Once you've got data in the database, you can quickly retrieve your blog posts
as well::

    >>> for post in connection.BlogPost.find():
    ...     print post['title']
    ... 
    my first blog post

pymongo_ makes it very easy to perform complex queries on your data so for more
information, see the :doc:`query` documentation.

