我讨厌这类问题,但也许你可以指出我很明显。我正在使用Mongo 2.2.2。
我有一个带有6M文档的集合(在副本集中),其中包含名为 username 的字符串字段,我有索引。该指数并非独一无二,但最近我将其独特。突然之后,查询给了我错误警报,我有重复。
db.users.aggregate(
{ $group : {_id : "$username", total : { $sum : 1 } } },
{ $match : { total : { $gte : 2 } } },
{ $sort : {total : -1} } );
返回
{
"result" : [
{
"_id" : "davidbeges",
"total" : 2
},
{
"_id" : "jesusantonio",
"total" : 2
},
{
"_id" : "elesitasweet",
"total" : 2
},
{
"_id" : "theschoolofbmx",
"total" : 2
},
{
"_id" : "longflight",
"total" : 2
},
{
"_id" : "thenotoriouscma",
"total" : 2
}
],
"ok" : 1
}
我在几个文档的样本集上测试了这个查询,它按预期工作。
答案 0 :(得分:2)
10gen之一在他们的JIRA中做出回应。
这个系列有什么更新吗?如果是这样,我会尝试将{$ sort:{username:1}}添加到管道的前面。这将确保您只看到每个用户名一次,如果它是唯一的。 如果有更新,如果文档因增长而移动,则聚合可能会看到文档两次。另一种可能性是,在聚合看到文档后,文档被删除,并且使用相同的用户名插入了新文档。
因此,在分组之前按username
排序有帮助。
答案 1 :(得分:0)
我认为答案可能在于你的$group
没有使用索引,它只是对整个集合进行扫描。这些运算符当前可以在聚合框架中使用和索引:
$match $sort $limit $skip
如果放在它们之前它们会起作用:
$project $unwind $group
但是,$group
本身不会使用索引。当你进行find()
测试时,我打赌你正在使用索引,可能作为覆盖索引(你可以通过查看该查询的explain()
进行验证),而不是扫描集合。基本上我的理论是你的索引没有欺骗,但你的收藏确实如此。
编辑:这可能是因为文档在聚合操作期间被更新/移动,因此被看到两次,而不是因为最初认为的集合中的欺骗。
如果您在管道中添加了一个可以使用索引但不会改变输入$group
的结果的运算符,那么您可以避免此问题。