diff --git a/README.md b/README.md new file mode 100644 index 0000000..ab8002c --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +MongoMallard +============ + +MongoMallard is a fast ORM-like layer on top of PyMongo, based on MongoEngine. + +* Repository: https://github.com/elasticsales/mongomallard +* See [README_MONGOENGINE](https://github.com/elasticsales/mongomallard/blob/master/README_MONGOENGINE.rst) for MongoEngine's README. +* See [DIFFERENCES](https://github.com/elasticsales/mongomallard/blob/master/DIFFERENCES.md) for differences between MongoEngine and MongoMallard. + + +Benchmarks +---------- + +Sample run on a 2.7 GHz Intel Core i5 running OS X 10.8.3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MongoEngine 0.8.2 (ede9fcf)MongoMallard (478062c)Speedup
Doc initialization52.494us25.195us2.08x
Doc getattr1.339us0.584us2.29x
Doc setattr3.064us2.550us1.20x
Doc to mongo49.415us26.497us1.86x
Load from SON61.475us4.510us13.63x
Save to database434.389us289.972us2.29x
Load from database558.178us480.690us1.16x
Save/delete big object to database98.838ms65.789ms1.50x
Serialize big object from database31.390ms20.265ms1.55x
Load big object from database41.159ms1.400ms29.40x
+ +See [tests/benchmark.py](https://github.com/elasticsales/mongomallard/blob/master/tests/benchmark.py) for source code. diff --git a/README.rst b/README_MONGOENGINE.rst similarity index 100% rename from README.rst rename to README_MONGOENGINE.rst diff --git a/mongoengine/__init__.py b/mongoengine/__init__.py index 5bd1201..875c916 100644 --- a/mongoengine/__init__.py +++ b/mongoengine/__init__.py @@ -16,6 +16,7 @@ __all__ = (list(document.__all__) + fields.__all__ + connection.__all__ + list(queryset.__all__) + signals.__all__ + list(errors.__all__)) VERSION = (0, 8, 2) +MALLARD = True def get_version(): diff --git a/mongoengine/base/proxy.py b/mongoengine/base/proxy.py index 4d92462..7d2879b 100644 --- a/mongoengine/base/proxy.py +++ b/mongoengine/base/proxy.py @@ -180,9 +180,6 @@ class DocumentProxy(LocalProxy): def _get_current_object(self): if self.__document == None: - #print 'fetching', self.__document_type, self.__pk - #import traceback - #traceback.print_stack() collection = self.__document_type._get_collection() son = collection.find_one({'_id': self.__pk}) document = self.__document_type._from_son(son) diff --git a/tests/benchmark.py b/tests/benchmark.py new file mode 100644 index 0000000..89439f3 --- /dev/null +++ b/tests/benchmark.py @@ -0,0 +1,90 @@ +from mongoengine import * +from timeit import repeat +import unittest + +conn_settings = { + 'db': 'mongomallard-test', +} + +connect(**conn_settings) + +def timeit(f, n=10000): + return min(repeat(f, repeat=3, number=n))/float(n) + +class BenchmarkTestCase(unittest.TestCase): + def setUp(self): + pass + + def test_basic(self): + class Book(Document): + name = StringField() + pages = IntField() + tags = ListField(StringField()) + is_published = BooleanField() + + Book.drop_collection() + + create_book = lambda: Book(name='Always be closing', pages=100, tags=['self-help', 'sales'], is_published=True) + print 'Doc initialization: %.3fus' % (timeit(create_book, 1000) * 10**6) + + b = create_book() + + print 'Doc getattr: %.3fus' % (timeit(lambda: b.name, 10000) * 10**6) + + print 'Doc setattr: %.3fus' % (timeit(lambda: setattr(b, 'name', 'New name'), 10000) * 10**6) + + print 'Doc to mongo: %.3fus' % (timeit(b.to_mongo, 1000) * 10**6) + + def save_book(): + b._mark_as_changed('name') + b._mark_as_changed('tags') + b.save() + + save_book() + son = b.to_mongo() + + print 'Load from SON: %.3fus' % (timeit(lambda: Book._from_son(son), 1000) * 10**6) + + print 'Save to database: %.3fus' % (timeit(save_book, 100) * 10**6) + + print 'Load from database: %.3fus' % (timeit(lambda: Book.objects[0], 100) * 10**6) + + def test_embedded(self): + class Contact(EmbeddedDocument): + name = StringField() + title = StringField() + address = StringField() + + class Company(Document): + name = StringField() + contacts = ListField(EmbeddedDocumentField(Contact)) + + Company.drop_collection() + + def get_company(): + return Company( + name='Elastic', + contacts=[ + Contact( + name='Contact %d' % x, + title='CEO', + address='Address %d' % x, + ) + for x in range(1000)] + ) + + def create_company(): + c = get_company() + c.save() + c.delete() + + print 'Save/delete big object to database: %.3fms' % (timeit(create_company, 10) * 10**3) + + c = get_company().save() + + print 'Serialize big object from database: %.3fms' % (timeit(c.to_mongo, 100) * 10**3) + print 'Load big object from database: %.3fms' % (timeit(lambda: Company.objects[0], 100) * 10**3) + + +if __name__ == '__main__': + unittest.main()