tmp work on migration doc
This commit is contained in:
parent
2f4464ead5
commit
f8d371229e
@ -16,3 +16,4 @@ User Guide
|
|||||||
text-indexes
|
text-indexes
|
||||||
logging-monitoring
|
logging-monitoring
|
||||||
mongomock
|
mongomock
|
||||||
|
migration
|
||||||
|
70
docs/guide/migration.rst
Normal file
70
docs/guide/migration.rst
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
==============================
|
||||||
|
Handling migration
|
||||||
|
==============================
|
||||||
|
|
||||||
|
The structure of your documents and their associated mongoengine schemas are likely
|
||||||
|
to change over the lifetime of an application. This section provides guidance and
|
||||||
|
recommendations on how to deal with migrations.
|
||||||
|
|
||||||
|
Due to the very flexible nature of mongodb, migrations of models aren't trivial and
|
||||||
|
for people that know about `alembic` for `sqlalchemy`, there is unfortunately no equivalent
|
||||||
|
library that will manage the migration in an automatic fashion for mongoengine.
|
||||||
|
|
||||||
|
First of all, let's take a simple example of model change and review the different option you
|
||||||
|
have to deal with the migration.
|
||||||
|
|
||||||
|
Let's assume we start with the following schema and save an instance:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class User(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
User(name=username).save()
|
||||||
|
|
||||||
|
# print the objects as they exist in mongodb
|
||||||
|
print(User.objects().as_pymongo()) # [{u'_id': ObjectId('5d06b9c3d7c1f18db3e7c874'), u'name': u'John'}]
|
||||||
|
|
||||||
|
On the next version of your application, let's now assume that a new field `enabled` gets added to the
|
||||||
|
existing User model with a `default=True`. Thus you simply update the `User` class to the following:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class User(Document):
|
||||||
|
name = StringField(required=True)
|
||||||
|
enabled = BooleaField(default=True)
|
||||||
|
|
||||||
|
Without migration, we now reload an object from the database into the `User` class and checks its `enabled`
|
||||||
|
attribute:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
assert User.objects.count() == 1
|
||||||
|
user = User.objects().first()
|
||||||
|
assert user.enabled is True
|
||||||
|
print(User.objects(enabled=True).count()) # 0 ! uh?
|
||||||
|
print(User.objects(enabled=False).count()) # 0 ! uh?
|
||||||
|
|
||||||
|
# but this is consistent with what we have in database
|
||||||
|
print(User.objects().as_pymongo().first()) # {u'_id': ObjectId('5d06b9c3d7c1f18db3e7c874'), u'name': u'John'}
|
||||||
|
assert User.objects(enabled=None).count() == 1
|
||||||
|
|
||||||
|
As you can see, even if the document wasn't updated, mongoengine applies the default value seemlessly when it
|
||||||
|
loads the pymongo dict into a `User` instance. At first sight it looks like you don't need to migrate the
|
||||||
|
existing documents when adding new fields but this actually leads to inconsistencies when it comes to querying.
|
||||||
|
|
||||||
|
In fact, when querying, mongoengine isn't trying to account for the default value of the new field and so
|
||||||
|
if you don't actually migrate the existing documents, you are taking a risk that querying/updating
|
||||||
|
will be missing relevant record.
|
||||||
|
|
||||||
|
When adding fields/modifying default values, you can use any of the following to do the migration
|
||||||
|
as a standalone script:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
User.objects().update(enabled=True)
|
||||||
|
# or
|
||||||
|
user_coll = User._get_collection()
|
||||||
|
user_coll.update_many({}, {'$set': {'enabled': True}})
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user