【问题标题】:In mongo how to efficiently sort and find get the last value matching the query?在 mongo 中如何有效地排序和查找得到匹配查询的最后一个值?
【发布时间】:2018-08-26 15:14:20
【问题描述】:

假设我有一些记录如下:

{
  id: 1,
  age: 22,
  name: 'A',
  class: 'Y'
},
{
  id: 2,
  age: 25,
  name: 'B',
  class: 'D'
},
{
  id: 3,
  age: 30,
  name: 'C',
  class: 'Y'
},
{
  id: 4,
  age: 40,
  name: 'D',
  class: 'B'
}

现在我需要获取年龄小于 28 岁的最后(最近)记录。为此,我可以使用以下代码:

const firstUsersYoungerThan28 = await Users.find({
  class: 'C',
  age: {
    $lt: 28
  }
})
  .sort({
    age: -1
  })
  .limit(1)
  .lean();

const firstUserYoungerThan28 = firstUsersYoungerThan28[0];

假设集合有数百万条记录。我的问题是,这是最有效的方法吗?有没有更好的方法来做到这一点?

我最担心的是,我的应用程序是否首先将记录加载到内存中以便对它们进行排序?

【问题讨论】:

    标签: mongodb mongoose


    【解决方案1】:

    查看有关cursor.sort()的文档:

    限制结果

    您可以将 sort() 与 limit() 结合使用来返回第一个(在 排序条件)k 个文档,其中 k 是指定的限制。

    如果 MongoDB 无法通过索引扫描获取排序顺序,则 MongoDB 使用 top-k 排序算法。该算法缓冲第一个 k 个结果(或最后一个,取决于排序顺序) 底层索引或集合访问。如果在任何时候记忆 这 k 个结果的占用空间超过 32 兆字节,查询将 失败。

    确保您在age 上有一个索引。然后,当 MongoDB 进行排序时,它只会将第一个 k(在您的情况下为 1)结果保留在内存中。

    MongoDB 可以为此类基本查询处理数百万个文档,不用担心。只需确保您确实指定了正确的索引。

    【讨论】:

      【解决方案2】:

      您应该创建一个具有以下属性的索引:

      1. 该索引过滤所有 28 岁以下的人
      2. 索引按 currentMeterReading 排序。

      这种类型的索引是部分索引。请参阅documentation about partial indexesusing indexes for sorting 了解更多信息。

      以下索引应该可以解决问题: db.users.createIndex( { age: -1, currentMeterReading: -1}, { partialFilterExpression: { age: {$lt: 28} } )

      如果没有索引,可能会按顺序进行完整扫描,这对性能非常不利。
      使用索引,只有您指定的列将存储在内存中(如果可能),搜索它们会更快。
      请注意,在某些或所有情况下,MongoDB 可能会延迟加载索引的值,而不是在创建索引时加载。这是一个实现选择。

      据我所知,没有办法创建只包含最后一条记录的索引。

      如果您想了解数据库的工作原理,您必须了解 indexes 的工作原理,特别是 B-Trees。 B 树是所有数据库的非常常见的结构。
      Indexes do have their disadvantages 所以不要为每个查询创建一个。始终在创建索引之前进行测量,因为它可能没有必要。

      【讨论】:

      • 抱歉,我更新了示例以更好地解释需求。但即使在那之后,使用这个索引也会为年龄小于 28 的记录创建一个永久索引,对吗?在搜索中,年龄值不时变化。
      • 如果年龄标准发生变化,您必须在没有partialFilterExpression 的情况下为整个年龄列编制索引,或者如果值的选择很少,则必须创建多个索引。
      • 您也可以在 MongoDB 中创建一个带有 TTL 的临时索引,但这是以索引过期时重建为代价的。
      猜你喜欢
      • 1970-01-01
      • 2013-06-24
      • 2022-11-25
      • 1970-01-01
      • 2021-07-27
      • 1970-01-01
      • 2020-12-14
      • 1970-01-01
      • 2020-10-12
      相关资源
      最近更新 更多