是否有更好的方法在没有阴影列的MongoDB中进行不区分大小写的排序?

时间:2014-09-27 01:05:52

标签: mongodb

我有几个对象需要执行不区分大小写的排序。我被告知我不能将阴影列添加到数据库以规范化值。因此我使用聚合来对输出进行排序。

我有一个简单的对象表示如下:

_id:ObjectID

createdOn:时间对象已创建

lastUpdatedOn:上次更新时间对象

name:对象的名称

isActive:表示对象当前是否处于活动状态的布尔值

这是我的聚合函数:

db.organization.aggregate(
    [
        {
            $match: { isActive: true }
        },
        {
            $project: {
                      lastUpdatedOn: 1,
                      createdOn: 1,
                      name: 1,
                      normalizedName: {$toLower: "$name"}
                      }
        },
        {
            $sort: { normalizedName: 1 }
        },
        {
            $project: {
                      lastUpdatedOn: 1,
                      createdOn: 1,
                      name: 1
                      }
        }
    ]
)

它首先确保我们只处理活动对象,为我们的排序创建规范化字段,执行排序,然后删除规范化字段,使其不暴露给用户。它工作并根据名称字段按字母顺序放置所有对象,但我不知道是否有更好的方法。

3 个答案:

答案 0 :(得分:2)

这不一定是一个显着的改进,但根据您的具体用例,将$$ROOT投影到与临时排序列分开的原始文档可以更清晰:

db.organization.aggregate(
    [
        {
            $match: { isActive: true }
        },
        {
            $project: {
                      doc: '$$ROOT'
                      normalizedName: {$toLower: "$name"}
                      }
        },
        {
            $sort: { normalizedName: 1 }
        },
        {
            $project: { doc: 1 }
        }
    ]
)

缺点是你最终在doc属性中关闭了原始文档,但是通过像Array#map之类的东西很容易清理客户端。或者您可以修改最终$project以将每个字段提升到顶级,但这可能很乏味。

答案 1 :(得分:0)

虽然MondoDB不提供它,但您可以使用PHP或任何其他语言轻松完成。以下是如何在PHP中完成它。

$cn = new MongoClient($dbHost);
$db = $cn->selectDB($dbName);
$col = new MongoCollection($db, $collectionName);

$cursor = $col->find();
$cursor = iterator_to_array($cursor);

foreach ($cursor as $key => $row) {
    $name[$key] = $row['name'];
    $email[$key] = $row['email'];
}
//$name is the field to sort on, taken from the above loop
//You can use SORT_ASC or SORT_DESC

array_multisort($name, SORT_ASC, $cursor);

foreach ($cursor as $doc) {
    echo $doc['name'].'-'.$doc['email'].'<br/>';
}

答案 2 :(得分:0)

我意识到这是一个老问题,但由于支持Mongo 3.4 Collation,这使得这更容易。对于使用排序规则进行聚合,只需附加一个如下所示的排序规则对象: db.organization.aggregate([pipelineobjs],{collation: {locale:'en_US'}})

我相信您的具体汇总方式如下:

db.organization.aggregate(
    [
        {
            $match: { isActive: true }
        },
        {
            $project: {
                      lastUpdatedOn: 1,
                      createdOn: 1,
                      name: 1
                      }
        },
        {
            $sort: { name: 1 }
        },
        {
            $project: {
                      lastUpdatedOn: 1,
                      createdOn: 1,
                      name: 1
                      }
        }
    ],
    {collation: {locale:'en_US'}}
)