1

我讨厌这种问题,但也许你可以指出我很明显。我正在使用 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
}

我用很少的文档在样本集合上测试了这个查询,它按预期工作。

4

2 回答 2

2

10gen 之一在他们的 JIRA 中做出了回应。

这个系列有更新吗?如果是这样,我会尝试将 {$sort: {username:1}} 添加到管道的前面。这将确保您只看到每个用户名(如果它是唯一的)一次。如果有更新正在进行,那么聚合可能会在文档因增长而移动时看到两次。另一种可能性是文档在被聚合查看后被删除,并且插入了具有相同用户名的新文档。

因此,username在分组之前进行排序会有所帮助。

于 2012-12-13T22:06:20.723 回答
0

我认为答案可能在于您$group没有使用索引,它只是对整个集合进行扫描。这些操作符当前可以在聚合框架中使用和索引:

$match $sort $limit $skip

如果放在之前,它们将起作用:

$project $unwind $group

但是,$group它本身不会使用索引。当您进行find()测试时,我敢打赌您正在使用索引,可能是作为覆盖索引(您可以通过查看explain()该查询来验证),而不是扫描集合。基本上我的理论是你的索引没有欺骗,但你的收藏有。

编辑:这可能是因为文档在聚合操作期间被更新/移动,因此被看到两次,而不是因为最初认为的集合中的重复。

如果您在管道中较早添加一个可以使用索引但不更改输入的结果的运算符$group,那么您可以避免该问题。

于 2012-12-13T10:06:43.557 回答