import unittest import warnings from pymongo.read_preferences import ReadPreference from mongoengine import * from tests.utils import MongoDBTestCase class TestQuerysetAggregate(MongoDBTestCase): def test_read_preference_aggregation_framework(self): class Bar(Document): txt = StringField() meta = {"indexes": ["txt"]} # Aggregates with read_preference pipeline = [] bars = Bar.objects.read_preference( ReadPreference.SECONDARY_PREFERRED ).aggregate(pipeline) assert ( bars._CommandCursor__collection.read_preference == ReadPreference.SECONDARY_PREFERRED ) def test_queryset_aggregation_framework(self): class Person(Document): name = StringField() age = IntField() Person.drop_collection() p1 = Person(name="Isabella Luanna", age=16) p2 = Person(name="Wilson Junior", age=21) p3 = Person(name="Sandra Mara", age=37) Person.objects.insert([p1, p2, p3]) pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] data = Person.objects(age__lte=22).aggregate(pipeline) assert list(data) == [ {"_id": p1.pk, "name": "ISABELLA LUANNA"}, {"_id": p2.pk, "name": "WILSON JUNIOR"}, ] pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] data = Person.objects(age__lte=22).order_by("-name").aggregate(pipeline) assert list(data) == [ {"_id": p2.pk, "name": "WILSON JUNIOR"}, {"_id": p1.pk, "name": "ISABELLA LUANNA"}, ] pipeline = [ {"$group": {"_id": None, "total": {"$sum": 1}, "avg": {"$avg": "$age"}}} ] data = ( Person.objects(age__gte=17, age__lte=40) .order_by("-age") .aggregate(pipeline) ) assert list(data) == [{"_id": None, "avg": 29, "total": 2}] pipeline = [{"$match": {"name": "Isabella Luanna"}}] data = Person.objects().aggregate(pipeline) assert list(data) == [{"_id": p1.pk, "age": 16, "name": "Isabella Luanna"}] def test_queryset_aggregation_with_skip(self): class Person(Document): name = StringField() age = IntField() Person.drop_collection() p1 = Person(name="Isabella Luanna", age=16) p2 = Person(name="Wilson Junior", age=21) p3 = Person(name="Sandra Mara", age=37) Person.objects.insert([p1, p2, p3]) pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] data = Person.objects.skip(1).aggregate(pipeline) assert list(data) == [ {"_id": p2.pk, "name": "WILSON JUNIOR"}, {"_id": p3.pk, "name": "SANDRA MARA"}, ] def test_queryset_aggregation_with_limit(self): class Person(Document): name = StringField() age = IntField() Person.drop_collection() p1 = Person(name="Isabella Luanna", age=16) p2 = Person(name="Wilson Junior", age=21) p3 = Person(name="Sandra Mara", age=37) Person.objects.insert([p1, p2, p3]) pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] data = Person.objects.limit(1).aggregate(pipeline) assert list(data) == [{"_id": p1.pk, "name": "ISABELLA LUANNA"}] def test_queryset_aggregation_with_sort(self): class Person(Document): name = StringField() age = IntField() Person.drop_collection() p1 = Person(name="Isabella Luanna", age=16) p2 = Person(name="Wilson Junior", age=21) p3 = Person(name="Sandra Mara", age=37) Person.objects.insert([p1, p2, p3]) pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] data = Person.objects.order_by("name").aggregate(pipeline) assert list(data) == [ {"_id": p1.pk, "name": "ISABELLA LUANNA"}, {"_id": p3.pk, "name": "SANDRA MARA"}, {"_id": p2.pk, "name": "WILSON JUNIOR"}, ] def test_queryset_aggregation_with_skip_with_limit(self): class Person(Document): name = StringField() age = IntField() Person.drop_collection() p1 = Person(name="Isabella Luanna", age=16) p2 = Person(name="Wilson Junior", age=21) p3 = Person(name="Sandra Mara", age=37) Person.objects.insert([p1, p2, p3]) pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] data = list(Person.objects.skip(1).limit(1).aggregate(pipeline)) assert list(data) == [{"_id": p2.pk, "name": "WILSON JUNIOR"}] # Make sure limit/skip chaining order has no impact data2 = Person.objects.limit(1).skip(1).aggregate(pipeline) assert data == list(data2) def test_queryset_aggregation_with_sort_with_limit(self): class Person(Document): name = StringField() age = IntField() Person.drop_collection() p1 = Person(name="Isabella Luanna", age=16) p2 = Person(name="Wilson Junior", age=21) p3 = Person(name="Sandra Mara", age=37) Person.objects.insert([p1, p2, p3]) pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] data = Person.objects.order_by("name").limit(2).aggregate(pipeline) assert list(data) == [ {"_id": p1.pk, "name": "ISABELLA LUANNA"}, {"_id": p3.pk, "name": "SANDRA MARA"}, ] # Verify adding limit/skip steps works as expected pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}, {"$limit": 1}] data = Person.objects.order_by("name").limit(2).aggregate(pipeline) assert list(data) == [{"_id": p1.pk, "name": "ISABELLA LUANNA"}] pipeline = [ {"$project": {"name": {"$toUpper": "$name"}}}, {"$skip": 1}, {"$limit": 1}, ] data = Person.objects.order_by("name").limit(2).aggregate(pipeline) assert list(data) == [{"_id": p3.pk, "name": "SANDRA MARA"}] def test_queryset_aggregation_with_sort_with_skip(self): class Person(Document): name = StringField() age = IntField() Person.drop_collection() p1 = Person(name="Isabella Luanna", age=16) p2 = Person(name="Wilson Junior", age=21) p3 = Person(name="Sandra Mara", age=37) Person.objects.insert([p1, p2, p3]) pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] data = Person.objects.order_by("name").skip(2).aggregate(pipeline) assert list(data) == [{"_id": p2.pk, "name": "WILSON JUNIOR"}] def test_queryset_aggregation_with_sort_with_skip_with_limit(self): class Person(Document): name = StringField() age = IntField() Person.drop_collection() p1 = Person(name="Isabella Luanna", age=16) p2 = Person(name="Wilson Junior", age=21) p3 = Person(name="Sandra Mara", age=37) Person.objects.insert([p1, p2, p3]) pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] data = Person.objects.order_by("name").skip(1).limit(1).aggregate(pipeline) assert list(data) == [{"_id": p3.pk, "name": "SANDRA MARA"}] def test_queryset_aggregation_deprecated_interface(self): class Person(Document): name = StringField() Person.drop_collection() p1 = Person(name="Isabella Luanna") p2 = Person(name="Wilson Junior") p3 = Person(name="Sandra Mara") Person.objects.insert([p1, p2, p3]) pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}] # Make sure a warning is emitted with warnings.catch_warnings(): warnings.simplefilter("error", DeprecationWarning) with self.assertRaises(DeprecationWarning): Person.objects.order_by("name").limit(2).aggregate(*pipeline) # Make sure old interface works as expected with a 1-step pipeline data = Person.objects.order_by("name").limit(2).aggregate(*pipeline) assert list(data) == [ {"_id": p1.pk, "name": "ISABELLA LUANNA"}, {"_id": p3.pk, "name": "SANDRA MARA"}, ] # Make sure old interface works as expected with a 2-steps pipeline pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}, {"$limit": 1}] data = Person.objects.order_by("name").limit(2).aggregate(*pipeline) assert list(data) == [{"_id": p1.pk, "name": "ISABELLA LUANNA"}] if __name__ == "__main__": unittest.main()