Fixed sum and average queryset function

* Fixed sum and average map reduce functions for sum and average so that
        it works with mongo dot notation.

* Added unittest cases / updated them for the new changes
This commit is contained in:
kelvinhammond 2013-06-21 09:39:11 -04:00
parent e0d2fab3c3
commit caff44c663
2 changed files with 60 additions and 3 deletions

View File

@ -1068,7 +1068,22 @@ class QuerySet(object):
""" """
map_func = Code(""" map_func = Code("""
function() { function() {
emit(1, eval("this." + field) || 0); function deepFind(obj, path) {
var paths = path.split('.')
, current = obj
, i;
for (i = 0; i < paths.length; ++i) {
if (current[paths[i]] == undefined) {
return undefined;
} else {
current = current[paths[i]];
}
}
return current;
}
emit(1, deepFind(this, field) || 0);
} }
""", scope={'field': field}) """, scope={'field': field})
@ -1098,8 +1113,24 @@ class QuerySet(object):
""" """
map_func = Code(""" map_func = Code("""
function() { function() {
if (this.hasOwnProperty(field)) function deepFind(obj, path) {
emit(1, {t: eval("this." + field) || 0, c: 1}); var paths = path.split('.')
, current = obj
, i;
for (i = 0; i < paths.length; ++i) {
if (current[paths[i]] == undefined) {
return undefined;
} else {
current = current[paths[i]];
}
}
return current;
}
val = deepFind(this, field)
if (val !== undefined)
emit(1, {t: val || 0, c: 1});
} }
""", scope={'field': field}) """, scope={'field': field})

View File

@ -30,12 +30,17 @@ class QuerySetTest(unittest.TestCase):
def setUp(self): def setUp(self):
connect(db='mongoenginetest') connect(db='mongoenginetest')
class PersonMeta(EmbeddedDocument):
weight = IntField()
class Person(Document): class Person(Document):
name = StringField() name = StringField()
age = IntField() age = IntField()
person_meta = EmbeddedDocumentField(PersonMeta)
meta = {'allow_inheritance': True} meta = {'allow_inheritance': True}
Person.drop_collection() Person.drop_collection()
self.PersonMeta = PersonMeta
self.Person = Person self.Person = Person
def test_initialisation(self): def test_initialisation(self):
@ -2208,6 +2213,19 @@ class QuerySetTest(unittest.TestCase):
self.Person(name='ageless person').save() self.Person(name='ageless person').save()
self.assertEqual(int(self.Person.objects.average('age')), avg) self.assertEqual(int(self.Person.objects.average('age')), avg)
# dot notation
self.Person(name='person meta', person_meta=self.PersonMeta(weight=0)).save()
self.assertAlmostEqual(int(self.Person.objects.average('person_meta.weight')), 0)
for i, weight in enumerate(ages):
self.Person(name='test meta%i', person_meta=self.PersonMeta(weight=weight)).save()
self.assertAlmostEqual(int(self.Person.objects.average('person_meta.weight')), avg)
self.Person(name='test meta none').save()
self.assertEqual(int(self.Person.objects.average('person_meta.weight')), avg)
def test_sum(self): def test_sum(self):
"""Ensure that field can be summed over correctly. """Ensure that field can be summed over correctly.
""" """
@ -2220,6 +2238,14 @@ class QuerySetTest(unittest.TestCase):
self.Person(name='ageless person').save() self.Person(name='ageless person').save()
self.assertEqual(int(self.Person.objects.sum('age')), sum(ages)) self.assertEqual(int(self.Person.objects.sum('age')), sum(ages))
for i, age in enumerate(ages):
self.Person(name='test meta%s' % i, person_meta=self.PersonMeta(weight=age)).save()
self.assertEqual(int(self.Person.objects.sum('person_meta.weight')), sum(ages))
self.Person(name='weightless person').save()
self.assertEqual(int(self.Person.objects.sum('age')), sum(ages))
def test_distinct(self): def test_distinct(self):
"""Ensure that the QuerySet.distinct method works. """Ensure that the QuerySet.distinct method works.
""" """