Docs 菜单

修改查询结果

在本指南中,您可以学习;了解如何自定义 Mongoid 返回查询结果的方式。 MongoDB允许您执行以下操作来修改结果的显示方式:

本指南中的示例使用 Band 模型,该模型表示乐队或音乐群组。 每个部分的 Band 模型的定义可能不同,以演示不同的查询功能。 某些部分还使用 Manager 模型(表示给定乐队的管理人员)或 Tour 模型(表示给定乐队的现场表演)。

在MongoDB中,投影是指定要从结果中包含或排除的字段的进程。Mongoid 提供以下操作符来项目字段:

  • only:指定要包含的字段

  • without:指定要排除的字段

only 方法只从数据库中检索指定字段。

以下代码仅返回 members字段值为 4 的文档中的 name字段:

Band.where(members: 4).only(:name)

注意

_id字段

在MongoDB中,即使您没有显式包含 _id字段也会包含在结果中。

如果尝试引用尚未加载的属性,Mongoid 会引发 Mongoid::Errors::AttributeNotLoaded 错误。

您还可以使用 only 方法包含嵌入式文档中的字段。

假设 Band 模型嵌入了多个 Tour 对象。 您可以项目Tour 模型中的字段,例如 year,如以下代码所示:

bands = Band.only(:name, 'tours.year')

然后,您可以从返回的文档访问权限嵌入式字段:

# Returns the first Tour object from
# the first Band in the results
bands.first.tours.first

您可以将引用关联的字段传递给 only 方法,但在加载嵌入式对象时会忽略投影。 Mongoid 加载引用关联的所有字段。 示例,当您访问权限前面代码中所示的嵌入式 Tour对象时,Mongoid 返回完整的对象,而不仅仅是 year字段。

注意

如果您连接到运行MongoDB 4.4 或更高版本的部署,则无法在同一查询中的投影中指定关联及其字段。

如果文档包含 has_onehas_and_belongs_to_many 关联,并且您希望 Mongoid 在调用 only 方法时加载这些关联,则必须在属性列表中包含带有外键的字段。

在以下示例中,BandManager 模型具有 has_and_belongs_to_many 关联:

class Band
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :managers
end
class Manager
include Mongoid::Document
has_and_belongs_to_many :bands
end

以下代码演示了如果包含 manager_ids字段, Mongoid 如何加载关联的 Manager 对象:

# Returns null
Band.where(name: 'Astral Projection').only(:name).first.managers
# Returns the first Manager object
Band.where(name: 'Astral Projection').only(:name, :manager_ids).first.managers

您可以使用 without 方法从结果中明确排除字段。

以下代码从返回的 Band 对象中排除 year字段:

Band.where(members: 4).without(:year)

重要

_id字段

Mongoid 需要_id 字段来执行各种操作,因此您不能从结果中排除 _id字段或id 别名。如果将 _idid 传递给 without 方法,Mongoid 会将其忽略。

您可以使用 orderorder_by 方法指定 Mongoid 返回文档的顺序。

这些方法接受一个哈希值,该哈希值指示按哪些字段对文档进行排序,以及对每个字段使用升序还是降序。

可以使用整数、符号或字符串指定排序方向。 为了一致性,我们建议在整个应用程序中使用相同的排序语法。 以下列表提供了每种语法,并显示了如何对 nameyear 字段进行排序:

  • 整数 1(升序)和 -1(降序)

    • 示例: Band.order(name: 1, year: -1)

  • 符号 :asc:desc

    • 示例: Band.order(name: :asc, year: :desc)

  • 字符串 "asc""desc"

    • 示例: Band.order_by(name: "asc", year: "desc")

order 方法还接受以下排序规范:

  • 二元素数组的数组:

    • 字符串

      • 示例: Band.order([['name', 'asc'], ['year', 'desc']])

    • 符号

      • 示例: Band.order([[:name, :asc], [:year, :desc]])

  • asc 以及针对符号的 desc 方法

    • 示例: Band.order(:name.asc, :year.desc)

  • SQL语法

    • 示例: Band.order('name asc', 'year desc')

提示

除了使用 orderorder_by 之外,您还可以使用 ascdesc 方法来指定排序顺序:

Band.asc('name').desc('year')

当您链式排序规范时,第一次调用定义第一个排序顺序,最后一个调用定义应用先前排序后的最后一个排序顺序。

注意

按范围排序

如果在包含排序规范的模型上定义 默认作用域,则作用域排序优先于查询中指定的排序,因为首先会评估默认作用域。

Mongoid 提供了可在 Criteria 对象上使用的 limitskipbatch_size 分页方法。 以下部分介绍了如何使用这些操作符。

您可以使用 limit 方法来限制 Mongoid 返回的结果数量。

以下代码最多检索 5 个文档:

Band.limit(5)

注意

或者,可以使用 take 方法从数据库中检索指定数量的文档:

Band.take(5)

您可以使用 skip 方法或其别名 offset 跳过指定数量的结果。

如果将 limit 调用链接到 skip,则在跳过文档后应用限制,如以下示例所示:

Band.skip(2).limit(5)
# Skips the first two results and returns
# the following five results

提示

执行分页时,对排序结果使用skip 以确保结果一致。

以下代码在返回结果时跳过前 3 个文档:

Band.skip(3)
# Equivalent
Band.offset(3)

执行大型查询以及使用Criteria#each 等枚举器方法迭代查询结果时,Mongoid 会自动使用MongoDB getMore 命令分批加载结果。默认批处理大小为 1000,但您可以使用 batch_size 方法设立不同的值。

以下代码将批处理大小设置为 500

Band.batch_size(500)

如需学习;了解有关构建查询的更多信息,请参阅“指定文档查询”指南。

要学习;了解Mongoid 数据建模,请参阅对数据建模指南。