持久化配置
文档存储
默认情况下,Mongoid 将文档存储在集合中,该集合是类名的复数形式。 对于以下 Person
类,存储文档的集合将命名为people
。
class Person include Mongoid::Document end
模型类名称不能以“s”结尾,因为它将被视为单词的复数形式。 示例,“Status”将被视为“Statu”的复数形式,这会导致一些已知问题。
这是ActiveSupport::Inflector#classify
的限制,Mongoid 使用 将文件名和集合名称转换为类名。 您可以通过为模型类指定自定义变形规则来克服这个问题。 例如,以下代码将处理名为Status
的模型。
ActiveSupport::Inflector.inflections do |inflect| inflect.singular("status", "status") end
如果您希望模型文档的集合在其他地方持久保留,则可以在类级别更改它们。 您还可以更改模型持久保存的数据库和客户端的默认值。
class Person include Mongoid::Document store_in collection: "citizens", database: "other", client: "analytics" end
store_in
宏还可以采用 lambda — 常见的情况是多租户应用程序。
class Band include Mongoid::Document store_in database: ->{ Thread.current[:database] } end
当文档存储在数据库中时,Ruby对象将被序列化为BSON ,并具有如下结构:
{ "_id" : ObjectId("4d3ed089fb60ab534684b7e9"), "title" : "Sir", "name" : { "_id" : ObjectId("4d3ed089fb60ab534684b7ff"), "first_name" : "Durran" }, "addresses" : [ { "_id" : ObjectId("4d3ed089fb60ab534684b7e0"), "city" : "Berlin", "country" : "Deutschland" } ] }
持久性上下文属性
Mongoid 在模型类上提供了client_name
、 database_name
和collection_name
方法,以确定用于持久性的客户端、数据库和集合名称:
Band.client_name # => :default Band.database_name # => "mongoid" Band.collection_name # => :bands
自定义分析器
在某些情况下,您可能希望将文档持久保存到不同于默认值的不同源,或者使用不同于默认值的不同选项。 Mongoid 对此提供运行时支持以及基于每个模型的支持。
模型级持久性选项
您可以在每个模型的基础上,将名称、不同的数据库或不同的客户端存储在自定义集合中。 默认,以下示例会将 Band 类存储到名为“music”的数据库中名为“artists”的集合中,客户端为“分析”。
请注意,为client
选项提供的值必须在 mongoid.yml 中的clients
下配置。
class Band include Mongoid::Document store_in collection: "artists", database: "music", client: "analytics" end
如果没有提供store_in
宏,Mongoid 会将模型存储在默认客户端默认数据库中名为“bands”的集合中。
运行时持久性选项
通过在模型类或实例上使用with
方法,可以更改用于一群组操作的持久性的客户端、数据库和集合以及任何MongoDB客户端选项:
Band.with(database: "music-non-stop") do |klass| klass.create(...) band = Band.first Band.create(...) end Band.with(collection: "artists") do |klass| klass.delete_all Band.delete_all end band.with(client: :tertiary) do |band_object| band_object.save! band.save! end
with
方法创建临时持久性上下文和用于在上下文中操作的MongoDB客户端。 在该区块的持续时间内,调用with
的模型类或实例上的持久性上下文将更改为临时持久性上下文。 为方便起见,调用with
的模型类或实例将生成为区块。
临时持久性上下文适用于查询和写入。
跨不同持久化上下文执行持久化操作时应谨慎。 示例,如果将文档保存在临时持久性上下文中,则它可能不存在于默认持久性上下文中,从而导致后续更新失败:
band = Band.new(name: "Scuba") band.with(collection: "artists") do |band_object| band_object.save! end # This will not save - updates the collection "bands" which does not have # the Scuba band band.update_attribute(likes: 1000) # This will update the document. band.with(collection: "artists") do |band_object| band_object.update_attribute(likes: 1000) end
从 Mongoid 6.0开始,必须始终使用区块调用with
方法,并且临时持久性上下文仅在区块期间存在。 这是因为会在幕后创建一个新客户端,并将选项传递给with
。 为了确保此客户端已关闭并释放其相关资源,必须明确定义可以使用此客户端的范围。
全局覆盖
如果您想在运行时切换所有操作的持久性上下文,但又不想在所有代码中使用,Mongoid 可以在全局范围内作为客户端和数据库级别执行此操作。 实现此目的的方法是Mongoid.override_client
和Mongoid.override_database
。 一个有用的案例是国际化应用程序,它们将不同区域设置的信息存储在不同的数据库或客户端中,但每个应用程序中的模式保持不变。
class BandsController < ApplicationController before_action :switch_database after_action :reset_database private def switch_database I18n.locale = params[:locale] || I18n.default_locale Mongoid.override_database("my_db_name_#{I18n.locale}") end def reset_database Mongoid.override_database(nil) end end
在上面的示例中,所有持久性操作都将存储在该线程上所有剩余操作的备用数据库中。 这就是为什么 after 请求将覆盖设置回零 - 它确保没有本地参数的后续请求使用默认选项。
持久性上下文适用于读取和写入操作。 例如,可以按如下方式执行从节点读取:
Band.with(read: {mode: :secondary}) do Band.count end
客户端和集合访问
如果要下拉到驾驶员级别执行操作,可以从模型或文档实例中获取mongo客户端或集合:
Band.mongo_client band.mongo_client Band.collection band.collection
从这里开始,您还可以使用客户端的#with
获得相同的运行时持久性选项:
client = Band.mongo_client.with(write: { w: 0 }, database: "musik") client[:artists].find(...)
您还可以使用集合#with
覆盖集合上的 :read 或 : 写入选项:
collection_w_0 = Band.collection.with(write: { w: 0 }) collection_w_0[:artists].find(...)