mongomock中的聚合中的$ sum似乎不起作用

时间:2018-11-20 19:36:08

标签: mongodb mongomock

我有一个汇总的Mongo查询,该查询会投影一些字段并使用 $ sum 计算另外两个字段。该查询按预期方式工作,因此我为其创建了一个单元测试,但令我惊讶的是测试失败。

我创建了一个minimal, complete, and verifiable example来检验我的假设,即这是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 是一个包含字符串名称,数字 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 运算符,但问题仍然相同,当应该为115时会产生100。

TL; DR;

问题:我应该如何在MongoMock上的聚合管道内使用 $ sum (或 $ add ),以便产生正确的值?

1 个答案:

答案 0 :(得分:0)

所描述的问题确实是Mongomock上的一个错误,该错误一直存在到3.14.0版本。

发布原始问题后,我在Mongomock的github上打开an issue描述问题。在修复它并在几天前发布3.15.0版本后不久。我运行了有关该问题的代码,现在 $ add $ sum 运算符都解决了该问题!

TL; DR

更新到Mongomock 3.15.0即可解决问题。