$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 достаточно для решения проблемы.

Другие вопросы по тегам