在mongo中如何有效地排序和查找与查询匹配的最后一个值?

时间:2018-03-17 17:10:03

标签: mongodb mongoose

我们说我有一些记录如下:

{
  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];

让我们说这个系列有数百万条记录。我的问题是,这是最有效的方式吗?有更好的方法吗?

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

2 个答案:

答案 0 :(得分:3)

请参阅有关cursor.sort()的文档:

  

限制结果

     

你可以使用sort()和limit()来返回第一个(in   排序顺序的条款)k个文件,其中k是指定的限制。

     

如果MongoDB无法通过索引扫描获取排序顺序,那么   MongoDB使用top-k排序算法。该算法缓冲第一个   到目前为止看到的k结果(或最后,取决于排序顺序)   底层索引或集合访问。如果在任何时候记忆   这些k结果的足迹超过32兆字节,查询将会   失败。

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

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

答案 1 :(得分:0)

您应该使用以下属性创建索引:

  1. 该指数会过滤年龄低于28
  2. 的所有人
  3. 索引按currentMeterReading排序。
  4. 此类索引是部分索引。有关详细信息,请参阅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所以不要为每个查询创建一个。始终在创建索引之前进行测量,因为它可能没有必要。