MongoDB查询区分、排序、限制和偏移

Posted

技术标签:

【中文标题】MongoDB查询区分、排序、限制和偏移【英文标题】:MongoDB query to distinct, sort, limit and offset 【发布时间】:2013-01-10 21:34:45 【问题描述】:

我正在寻找与以下类似的 Mongo:

select distinct event_type_id from events
order by created_at desc
limit 10,20

Event Mongo文档如下:


  _id: BSON(), event_type_id: 1, created_at: Date(), other_data: 

【问题讨论】:

【参考方案1】:

您可以在新的 mongo 版本上使用 Aggregation Framework。以下是开始的示例:

db.events.aggregate([
    $sort:"created_at":-1,
    $project:"event_type_id":1,
    $group:"_id":"$event_type_id",
    $skip:10,
    $limit:20
])

感谢@JoachimIsaksson,这是另一种方法

db.events.aggregate([
    $group:"_id":"$event_type_id", "created_at":$max:"$created_at",
    $sort:"created_at":-1,
    $skip:10,
    $limit:20,
    $project:"event_type_id":1
])

【讨论】:

有什么方法可以做不同的吗? 很抱歉,正在努力学习...... :) 你真的可以一个接一个地分组并保持顺序吗? 我一直在想一些事情; $group:_id:"$event_type_id", ord: $max:"$created_at",$sort:"ord":-1,$project:"event_type_id":1,$skip:10,$limit:20 但我在这里免费发短信,没有任何东西可以尝试:) @JoachimIsaksson SQL DISTINCT 命令依赖于数据库,但在大多数 SQL 数据库中,它是一个 $group,使用文档每个字段的 $min$max。 DISTINCT 查询有一个巨大的缺陷,但你无法确定,这取决于 db 实现。 @JoachimIsaksson 是的,你可以在 $group 中进行排序,检查我的编辑【参考方案2】:

您始终可以通过 v2.2 中引入的聚合框架来做到这一点:

db.col.aggregate(
    $group: _id: "$event_type_id", created_at: "$created_at",
    ($sort: "$created_at":-1
);

类似的东西会分组,这实际上与 distinct 相同,所有 event_type_id 值并按 created_at 降序排序。

这应该没问题,但请注意,目前它的输出限制 (atm) 为 16meg,因此如果您要输出一个巨大的文档,您可能会觉得很困难。

编辑

为了提高性能,您实际上可以先使用索引进行排序,然后再使用$group

db.col.aggregate(
     $sort: "$created_at":-1 ,
     $group: _id: "$event_type_id", created_at: $first: "$created_at" 
);

这使用$first (http://docs.mongodb.org/manual/reference/aggregation/first/) 运算符来获取该组中该字段的第一个值。您也可以使用$last 运算符,这些当然会转换为普通的$min$max,但用于排序集。

【讨论】:

您好,感谢$first 示例。如果我想在组之后添加过滤器,例如,如果我只想保留将 type 设置为 true 的项目,将 type: $first: '$type' 添加到 $group 然后添加新区块 $match: type: true 。这可以吗?或者有更好的方法吗? @Matteo no 在这种情况下,您将使用 $max ,因为您不能肯定地说排序集是您想要的 $first 或 $last ,因此您将在此实际获得该字段的 $max案例 $max 是什么?对于布尔字段,它没有任何意义。我的意思是,我的代码与您的示例非常相似。我按日期(“created_time”)排序,然后我想用另一个字段过滤结果,提取集合中的第一个(连同日期)。我这样做的方式似乎有效,但如果它是正确的,我就不会。 @Matteo 布尔字段转换为 1 和 0,1 表示真,0 表示假。 $max 将始终返回 true,但是,如果您排序的第一个分组日期的类型为 false,则 $first 可能会返回 false,但只有当日期可以具有不同的布尔值并且您希望优先于 true 时才会出现这种情况, 不是第一个排序的 @Matteo 归根结底,我可能对您的数据和场景了解得不够多,无法说明哪个是最好的,您可能会发现最好提出一个带有更详细解释的问题,然后可以回答。【参考方案3】:

我认为您不能在 mongo 中将限制和跳过命令与不同的查询结合使用。下面的代码将返回相当于下面的 sql 语句:

select distinct event_type_id from events
order by created_at desc

db.events.distinct( 'event_type_id', , createdAt: -1 )

检索结果后,您可以根据需要从中提取子集。您也可以查看以下帖子:How to use Distinct, Sort, limit with mongodb

显然这是mongo社区的公开票,你也可以检查问题,看起来他们暂时不会实现limit和distinct的组合https://jira.mongodb.org/browse/SERVER-2130

【讨论】:

我只能找到2 parameters to distinct 记录,你在哪里找到第三个? :) javascript 允许您调用具有任意数量参数的方法,但这不起作用。 但是它从 shell 给出了正确的结果,这怎么会发生? @cubbuk 它可能会按插入顺序返回结果,而该顺序恰好是您所期望的?通过升序排序是否可以反转顺序? 这就是我在更改排序查询时以降序或升序得到的结果。

以上是关于MongoDB查询区分、排序、限制和偏移的主要内容,如果未能解决你的问题,请参考以下文章

你如何告诉 Mongo 在限制结果之前对集合进行排序?

你如何告诉 Mongo 在限制结果之前对集合进行排序?

Elasticsearch+Mongo亿级别数据导入及查询实践

使用 MongoDB 在 Grails 中命名查询的列表方法中排序不区分大小写

Mongodb:聚合排序限制查询的索引?

Mongoose Mongodb 子文档的排序和限制查询