我有一个汇总的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 ),以便产生正确的值?
答案 0 :(得分:0)
所描述的问题确实是Mongomock上的一个错误,该错误一直存在到3.14.0版本。
发布原始问题后,我在Mongomock的github上打开an issue描述问题。在修复它并在几天前发布3.15.0版本后不久。我运行了有关该问题的代码,现在 $ add 和 $ sum 运算符都解决了该问题!
TL; DR
更新到Mongomock 3.15.0即可解决问题。