【问题标题】:mongodb aggregate, sort based on lookup resultmongodb聚合,根据查找结果排序
【发布时间】:2019-01-14 09:12:40
【问题描述】:

假设我有以下数据架构(我只报告几个字段)

收集顺序

| id    | service | customer |
|-------|---------|----------|
| O001  | SRV001  | CST001   |
| O002  | SRV001  | CST001   |
| O003  | SRV001  | CST002   |
| O004  | SRV002  | CST003   |
| O005  | SRV002  | CST002   |
| O006  | SRV003  | CST004   |

收集客户

| id     | name    | city     |
|--------|---------|----------|
| CST001 | Paul    | New York |
| CST002 | Anna    | London   |
| CST003 | John    | Milan    |
| CST004 | Julia   | Paris    |

假设我想根据客户姓名对订单进行排序

这个想法是使用带有 $lookup 的聚合来加入客户对结果进行排序和排序

db.order.aggregate([
   { $lookup: { 'foreignField': 'id', 
                'as': '__customer', 
                'from': 'customer', 
                'localField':'customer'} },
   { $unwind: '$__customer'},
   { $sort:   { '__customer.name': 1 } }
])

如果您的数据有限,这可以正常工作。如果您有大量数据,则它不起作用,因为排序是在 $lookup 结果上执行的,因此即使客户集合中的字段“名称”有索引,mongodb 也没有可使用的索引。

我认为没有办法做到这一点。

有人可以确认吗?

【问题讨论】:

    标签: mongodb sorting aggregation-framework


    【解决方案1】:

    Documentation 说:

    当 $match 和 $sort 管道运算符出现在管道的开始时,它们可以利用索引。

    还有更多:

    3.2 版更改:从 MongoDB 3.2 开始,索引可以覆盖聚合管道。在 MongoDB 2.6 和 3.0 中,索引无法覆盖聚合管道,因为即使管道使用索引,聚合仍然需要访问实际文档。

    据此,MongoDB(3.2 及更高版本)聚合使用索引。

    但是,您的管道有一些技巧。例如,您可以聚合 customer 表,而不是 order。对其进行排序,然后为orders 执行lookup

    或者你可以通过customergroup 然后lookup。我不认为它会更快(实际上我认为它会更慢),但你可以尝试考虑一下。

    别忘了使用matcheslimits - 它们可以加速聚合。即使在大型管道中,您通常也可以match 接近开始,但有时您需要好好思考。

    【讨论】:

    • 聚合客户表不是一个选项,因为关系不是一对一的
    • 我需要一个通用的解决方案,一些过滤器(通过匹配实现)可能存在,但最坏的情况是它不存在。
    • @lorenzo 你不需要一对一的关系。 lookup 对于字段 idunwind 确实为您提供 1 对 1 关系,但是当您通过 customer.name 获得 sort 时,您会得到 many orders to 1 customer 关系,这与排序 customers 相同和lookup 用于orders(没有unwind 用于orders)。您将获得一份包含客户的列表(其中包含订单列表)。在这里你有一个常见的情况 - 如果你只需要前 20 个订单,那么你可以限制(20)你的客户,然后 unwind 订单,按客户排序(因为 unwind 可以自行排序)并再次限制(20)。跨度>
    • @Lorenzo 只是为了确保我们谈论的是同一件事,这是我建议的管道:db.customer.aggregate([ {$sort: {'name': 1}}, {$lookup: { 'localField':'_id', 'from': 'order', 'foreignField': 'customer', 'as': 'orders', }}, {$match: {orders: {$gt: []}}}, {$limit: 20}, {$unwind: '$orders'}, {$limit: 20}, ])
    • 谢谢,我下周去看看。这周我不在家
    猜你喜欢
    • 2015-12-28
    • 2019-01-17
    • 2021-06-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 2021-10-26
    • 1970-01-01
    • 2020-03-17
    相关资源
    最近更新 更多