Ensuring Indexing¶
The ODM layer permits to ensure indexes over the collections by using the __mongometa__ attribute. You can enforce both unique indexing and non-unique indexing.
To apply the indexes sepcified in your models you can then iterate over all the mappers and
call Mapper.ensure_all_indexes()
to guarantee that indexes are created for every
registered mapper:
ming.odm.Mapper.ensure_all_indexes()
This needs to be performed each time you change the indexes or the database. It is common practice to ensure all the indexes at application startup.
Indexing a Field¶
Indexing a field is possible by just setting index=True
parameter when
creating a FieldProperty
:
class Permission(MappedClass):
class __mongometa__:
session = session
name = 'permissions'
_id = FieldProperty(s.ObjectId)
permission_name = FieldProperty(s.String, index=True)
description = FieldProperty(s.String)
groups = FieldProperty(s.Array(str))
More flexible indexes definition is also available through the
indexes
property of __mongometa__
:
class Permission(MappedClass):
class __mongometa__:
session = session
name = 'permissions'
indexes = [('permission_name', )]
_id = FieldProperty(s.ObjectId)
permission_name = FieldProperty(s.String)
description = FieldProperty(s.String)
groups = FieldProperty(s.Array(str))
Indexes are represented by tuples which can have one or more entries (to represent compound indexes):
indexes = [('permission_name', 'groups'),]
Also the tuples can contain a (field, direction)
declaration
to indicate where the index is sorted:
indexes = [
(('permission_name', ming.ASCENDING), ('groups', ming.DESCENDING))
]
Multiple indexes can be declared for a collection:
indexes = [
(('permission_name', ming.ASCENDING), ('groups', ming.DESCENDING)),
('groups', )
]
Unique Indexes¶
You can use unique_indexes
to ensure that it won’t be possible to duplicate
an object multiple times with the same name:
class Permission(MappedClass):
class __mongometa__:
session = session
name = 'permissions'
unique_indexes = [('permission_name',)]
_id = FieldProperty(s.ObjectId)
permission_name = FieldProperty(s.String)
description = FieldProperty(s.String)
groups = FieldProperty(s.Array(str))
Custom Indexes¶
If you want more control over your indexes, you can use custom_indexes directly within __mongometa__, this will allow you to explicitly set unique and/or sparse index flags that same way you could if you were directly calling ensureIndex in the MongoDB shell. For example, if you had a field like email that you wanted to be unique, but also allow for it to be Missing
class User(MappedClass):
class __mongometa__:
session = session
name = 'users'
custom_indexes = [
dict(fields=('email',), unique=True, sparse=True)
]
_id = FieldProperty(s.ObjectId)
email = FieldProperty(s.String, if_missing=s.Missing)
Indexes definitions in custom_indexes
can actually contain any
key which is a valid argument for Index
initialization function as
they are used to actually create Index
instances.
Now when accessing instances of User, if email is Missing and you attempt to use the User.email attribute Ming, will throw an AttributeError as it ensures that only properties that are not Missing are mapped as attributes to the class.
This brings us to the ming.odm.property.FieldPropertyWithMissingNone
property type. This allows you to mimic the behavior that you commonly find in a SQL
solution. An indexed and unique field that is also allowed to be NULL
or in this case Missing. A classic example would be a product database where you
want to enter in products but don’t have SKU numbers for them yet. Now your product listing
can still call product.sku without throwing an AttributeError.
class Product(MappedClass):
class __mongometa__:
session = session
name = 'products'
custom_indexes = [
dict(fields=('sku',), unique=True, sparse=True)
]
_id = FieldProperty(s.ObjectId)
sku = FieldPropertyWithMissingNone(str, if_missing=s.Missing)