$sum внутри агрегата в mongomock, кажется, не работает
У меня есть сводный запрос Монго, который проецирует некоторые поля и вычисляет два других, используя $sum. Запрос работает, как и ожидалось, поэтому я создал для него модульный тест, и, к моему удивлению, тест не прошел.
Я создал минимальный, полный и проверяемый пример, чтобы проверить свою гипотезу о том, что это проблема с MongoMock, и, похоже, это так!
Вот код:
import mongoengine as mongo
from mongoengine import connect
from mongoengine.queryset import QuerySet
class ValuesList(mongo.EmbeddedDocument):
updated_value = mongo.DecimalField()
class ValuesHistory(mongo.Document):
name = mongo.StringField()
base_value = mongo.DecimalField()
values_list = mongo.EmbeddedDocumentListField(ValuesList, required=False)
meta = {
'collection' : 'values_history'
}
def __str__(self):
return 'name: {}\nbase_value: {}\n'.format(self.name, self.base_value)
def migrate_data(new_collection):
ValuesHistory.objects.aggregate(
{'$project': {'name': 1,
'base_value': {'$sum': ['$base_value', {'$arrayElemAt': ['$values_list.updated_value', -1]}]}
}
},
{'$out': "{}".format(new_collection)}
)
def clear_tables_and_insert_test_data(db):
db.test.values_history.drop()
db.test.updated_values.drop()
ValuesHistory(name='first',
base_value=100,
values_list=[ValuesList(updated_value=5),
ValuesList(updated_value=15)]).save()
def run_aggregate_query_with_db(db):
new_collection_name = 'updated_values'
migrate_data(new_collection_name)
new_group = ValuesHistory.switch_collection(ValuesHistory(), new_collection_name)
aggregated_values = QuerySet(ValuesHistory, new_group._get_collection()).all()
for value in aggregated_values:
print(value)
db.close()
Краткое объяснение кода выше.
ValuesHistory - это класс, который содержит имя String, числовое base_value и список значений (классValuesList).
Метод clear_tables_and_insert_test_data очищает две таблицы, использованные в этом тесте, и вставляет некоторые данные теста.
Запрос в методе migrate_data создает новую коллекцию (через оператор $out), а base_value вновь созданной коллекции должно быть суммой текущего значения и последнего значения в списке values_list. В моем случае это должно быть 115 (100 текущее значение и 15 последнее значение в списке).
Если я запускаю код, используя соединение с моей локальной MongoDB, вот так:
if __name__ == '__main__':
db = connect('test') # connect to real instance of Mongo
clear_tables_and_insert_test_data(db)
run_aggregate_query_with_db(db)
В результате я получаю 115, и это именно то, что ожидается.
Если я вместо этого использую соединение с MongoMock:
if __name__ == '__main__':
db = connect('test', host='mongomock://localhost') # Connect to MongoMock instance
clear_tables_and_insert_test_data(db)
run_aggregate_query_with_db(db)
Я получаю 100 в результате, что странно! Похоже, оператор $sum не выполнил свою работу должным образом, так как сумма 100 и 15 привела к 100!
РЕДАКТИРОВАТЬ: Я также пытался использовать оператор $add, но проблема остается той же, получив 100, когда он должен быть 115.
TL; DR;
Вопрос: Как мне использовать $sum (или $add) внутри агрегатного конвейера в MongoMock, чтобы он давал правильное значение?
0 ответов
Описанная проблема действительно была ошибкой в Mongomock, существовавшей до версии 3.14.0.
После того, как исходный вопрос был опубликован, я открыл проблему на github Mongomock, описывающую проблему. Вскоре после того, как это было исправлено, и версия 3.15.0 была выпущена несколько дней назад. Я запустил код вопроса, и теперь проблема решена для операторов $add и $sum!
TL; DR
Обновление Mongomock 3.15.0 достаточно для решения проблемы.