Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
192 lines (121 sloc) 5.57 KB

Saving

There are a couple of different approaches that can be taken when writing data to a MongoDB database. Simon provides a few different methods to perform writes to help expose the full power of each.

Document Replacement

The basic way to create or update a document is with the :meth:`~simon.Model.save` method. It will save the document associated with the instance to the database. If an update is being performed, the version of the document in the database will be overwritten by the version associated with the instance. This is known as document replacement. Any changes made to the version of the document in the database that have not been introduced to the instance will be lost.

user = User(name='Simon')
user.save()

This can be condensed into one step using the :meth:`~simon.Model.create` method.

user = User.create(name='Simon')

:meth:`~simon.Model.save` can also be used to save changes to a document.

user.email = 'simon@example.com'
user.save()

The first of these calls to :meth:`~simon.Model.save` will result in an insert. The second will result in an update. In the mongo Shell they would be written as:

db.users.insert({name: 'Simon'})

db.users.update({_id: ObjectId(...)}, {email: 'simon@example.com'})

Atomic Updates

MongoDB also offers a more powerful way to save changes to documents: atomic updates. By utilizing atomic updates, you can write selective changes to portions of a document without replacing the whole thing. Simon provides several different ways to perform atomic updates.

save_fields

The :meth:`~simon.Model.save_fields` method will perform an atomic update updating only the specified fields.

# update only the score field
user.score = 100
user.save_fields('score')

You can also update multiple fields at once.

user.score = 200
user.friends = ['Alvin', 'Theodore']
user.save_fields(['score', 'friends'])

In the mongo Shell these would be:

db.users.update({_id: ObjectId(...)}, {$set: {score: 100}})

db.users.update({_id: ObjectId(...)}, {$set: {score: 200, friends: ['Alvin', 'Theodore']}})
update

The :meth:`~simon.Model.update` method provides a shortcut to the behavior offered by :meth:`~simon.Model.save_fields`.

user.update(score=100)

user.update(score=200, friends=['Alvin', 'Theodore'])
increment

The :meth:`~simon.Model.increment` method provides a way to increment the values of the specified fields. If the field does not exist, it will be added with the initial value of 0.

When incrementing only one field, only the name of the field needs to be given to :meth:`~simon.Model.increment`. A value can also be provided if incrementing by any value other than 1.

user.increment('score')

user.increment('score', 100)

:meth:`~simon.Model.increment` can also be used to increment multiple fields at once.

user.increment(score=100, level=1)

The equivalent queries in the mongo Shell would be:

db.users.update({_id: ObjectId(...)}, {$inc: {score: 1}})

db.users.update({_id: ObjectId(...)}, {$inc: {score: 100}})

db.users.update({_id: ObjectId(...)}, {$inc: {score: 100, level: 1}})
remove_fields

The :meth:`~simon.Model.remove_fields` method will remove the specified fields from the document in the database.

Using it works just like :meth:`~simon.Model.save_fields`.

user.remove_fields('level')

user.remove_fields(['level', 'friends'])

To execute these same queries in the mongo Shell:

db.users.update({_id: ObjectId(...)}, {$unset: {level: 1}})

db.users.update({_id: ObjectId(...)}, {$unset: {level: 1, friends: 1}})
raw_update

The :meth:`~simon.Model.raw_update` method allows any update query to be specified.

This method will let you execute any update that can't appropriately be expressed through one of the other methods. Just make sure you use it with caution as Simon can do little to protect you.

user.raw_update({'$set': {'level': 1}, '$inc': {'score': 100}, '$unset': {'friends': 1}})

This query would be passed through to MongoDB as:

db.users.update({_id: ObjectId(...)}, {$set: {level: 1}, $inc: {score: 100}, $unset: {friends: 1}})

Write Concern

Simon ships with write concern enabled for all updates by default. For an update to be successful, it must be successful or, in the case of a replica set, it must be successful on the primary server. All of the methods discussed above as well as :meth:`~simon.Model.delete` and :meth:`~simon.Model.get_or_create` accept an argument called w that can be used to override the default behavior. This can come in the form of disabling write concern with w=0 or making sure the update is replicated toa number of secondary servers with w=3. The latter will only be considered successful if write happens on the primary server and two secondary servers.

user = User(name='Simon')
user.save(w=0)

user.update(email='simon@example.com', safe=True)

user.delete(w=2)

A much more detailed explanation of write concern is available in the MongoDB Docs.