$sum inside aggregate in mongomock 似乎不起作用
$sum inside aggregate in mongomock seems not to be working
我有一个聚合 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 是一个 class,它包含一个字符串 name、一个数字 base_value 和值列表 (ValuesList class)。
方法clear_tables_and_insert_test_data清空本次测试用到的两张表,插入一些测试数据
migrate_data 方法中的查询创建一个新集合(通过 $out 运算符)和 [=42新建集合的=]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!
EDIT:我也尝试使用 $add 运算符,但问题仍然存在,当它应该是 115 时产生 100 .
TL;DR;
问题:我应该如何使用$sum(或$add)在 MongoMock 上聚合管道以便它产生正确的值?
所描述的问题确实是 Mongomock 上的一个错误,该错误一直存在到版本 3.14.0。
原问题发布后,我在 Mongomock 的 github 上打开 an issue 描述问题。修复后不久,3.15.0 版已于几天前发布。我 运行 问题的代码,现在 $add 和 $sum 运算符的问题都已解决!
TL;DR
更新到Mongomock 3.15.0即可解决问题
我有一个聚合 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 是一个 class,它包含一个字符串 name、一个数字 base_value 和值列表 (ValuesList class)。
方法clear_tables_and_insert_test_data清空本次测试用到的两张表,插入一些测试数据
migrate_data 方法中的查询创建一个新集合(通过 $out 运算符)和 [=42新建集合的=]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!
EDIT:我也尝试使用 $add 运算符,但问题仍然存在,当它应该是 115 时产生 100 .
TL;DR;
问题:我应该如何使用$sum(或$add)在 MongoMock 上聚合管道以便它产生正确的值?
所描述的问题确实是 Mongomock 上的一个错误,该错误一直存在到版本 3.14.0。
原问题发布后,我在 Mongomock 的 github 上打开 an issue 描述问题。修复后不久,3.15.0 版已于几天前发布。我 运行 问题的代码,现在 $add 和 $sum 运算符的问题都已解决!
TL;DR
更新到Mongomock 3.15.0即可解决问题