MongoDB find() 查询是否返回按创建时间排序的文档?

Dra*_*ag0 4 database sorting mongodb

我需要按创建时间排序的文档(从最旧到最新)。

由于 ObjectID 默认保存时间戳,我们可以使用它来获取按创建时间排序的文档CollectionName.find().sort({_id: 1})

另外,我注意到常规CollectionName.find()查询总是CollectionName.find().sort({_id: 1}).

我的问题是:

是否CollectionName.find()保证以相同的顺序返回文件,CollectionName.find().sort({_id: 1})以便我可以不用整理?

Ser*_*sev 5

CollectionName.find() 是否保证以与 CollectionName.find().sort({_id: 1}) 相同的顺序返回文档

不,这不对!如果您没有指定任何顺序,则使用所谓的“自然”排序。这意味着文档将按照它们在数据文件中实际出现的顺序返回。

现在,如果您只插入文档而从不修改它们,这种自然顺序将与升序一致_id。然而,想象一下,您以这样一种方式更新文档,它的大小会增加,并且必须移动到数据文件内的空闲插槽中(通常这意味着在文件末尾的某个位置)。如果您现在要查询文档,它们将不会遵循任何合理的(对外部观察者而言)顺序。

因此,如果您关心顺序,请明确说明。

来源:http : //docs.mongodb.org/manual/reference/glossary/#term-natural-order

自然秩序

数据库引用磁盘上文档的顺序。这是默认的排序顺序。参见 $natural 和 Return in Natural Order。

测试脚本(对于困惑的人)

> db.foo.insert({name: 'Joe'})
WriteResult({ "nInserted" : 1 })

> db.foo.insert({name: 'Bob'})
WriteResult({ "nInserted" : 1 })

> db.foo.find()
{ "_id" : ObjectId("55814b944e019172b7d358a0"), "name" : "Joe" }
{ "_id" : ObjectId("55814ba44e019172b7d358a1"), "name" : "Bob" }

> db.foo.update({_id: ObjectId("55814b944e019172b7d358a0")}, {$set: {answer: "On a sharded collection the $natural operator returns a collection scan sorted in natural order, the order the database inserts and stores documents on disk. Queries that include a sort by $natural order do not use indexes to fulfill the query predicate with the following exception: If the query predicate is an equality condition on the _id field { _id: <value> }, then the query with the sort by $natural order can use the _id index. You cannot specify $natural sort order if the query includes a $text expression."}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.foo.find()
{ "_id" : ObjectId("55814ba44e019172b7d358a1"), "name" : "Bob" }
{ "_id" : ObjectId("55814b944e019172b7d358a0"), "name" : "Joe", "answer" : "On a sharded collection the $natural operator returns a collection scan sorted in natural order, the order the database inserts and stores documents on disk. Queries that include a sort by $natural order do not use indexes to fulfill the query predicate with the following exception: If the query predicate is an equality condition on the _id field { _id: <value> }, then the query with the sort by $natural order can use the _id index. You cannot specify $natural sort order if the query includes a $text expression." }
Run Code Online (Sandbox Code Playgroud)


Mar*_*erg 5

不,不完全是。db.collection.find()大多数情况下,A将按照文档在数据文件中出现的顺序为您提供文档,但这并不能保证。

结果排序

除非指定 sort() 方法或使用 $near 运算符,否则 MongoDB 不保证查询结果的顺序。

只要您的数据文件相对较新并且很少发生更新,文档可能(并且大多数情况下)会以似乎排序的方式返回,_id因为 ObjectId 是单调递增的。

在生命周期的后期,旧文档可能已经从它们的旧位置移动(因为它们的大小增加了并且文档从不分区),而新文档被写入以前被另一个文档占据的位置。在这种情况下,可能会在两个旧文档之间的位置返回较新的文档。

按 对文档进行排序没有任何问题_id,因为索引将用于该目的,只会为文档检索增加一些延迟。

但是,出于以下几个原因,我强烈建议不要使用 ObjectId 进行日期操作:

  1. ObjectIds 不能用于日期比较查询。因此,您无法查询在日期 x 和日期 y 之间创建的所有文档。要存档,您必须加载所有文档,从 ObjectId 中提取日期并进行比较——这是非常低效的。
  2. 如果创建日期很重要,则应在文档中明确说明
  3. 我认为 ObjectIds 是该_id字段的最后选择,并且倾向于使用其他值(有时是复合值)作为_ids,因为该字段默认被索引,并且很可能可以通过使用更有意义的值来节省宝贵的 RAM作为身份证。

您可以使用以下示例,它利用DBRef s

{
  _id: {
    creationDate: new ISODate(),
    user: { 
      "$ref" : "creators",
      "$id" : "mwmahlberg",
      "$db" : "users"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

并通过使用进行相当便宜的排序

db.collection.find().sort({_id.creationDate:1})
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,您建议的这个技巧是能够使用 _id 上的免费索引对其子字段进行排序 - 它不起作用。子文档的索引非常有限。我从一开始就对此持怀疑态度,但今天早上我阅读了文档并进行了测试:https://gist.github.com/stulentsev/ad9525bfa2a1d620541e (2认同)