文档菜单
文档首页
/ / /
Mongoid
/

持久性配置

在本页

  • 文档存储
  • 持久性上下文属性
  • 自定义
  • 模型级别持久性选项
  • 运行时持久性选项
  • 客户端和集合访问

Mongoid默认将文档存储在以类名复数形式命名的集合中。对于以下Person类,文档将存储在名为people的集合中。

class Person
include Mongoid::Document
end

模型类名不能以"s"结尾,因为这会被视为单词的复数形式。例如,“Status”会被视为“Statu”的复数形式,这会导致一些已知问题。

这是Mongoid使用的ActiveSupport::Inflector#classify的限制,它用于将文件名和集合名转换为类名。您可以通过为模型类指定自定义屈折规则来克服这个问题。例如,以下代码将处理名为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_namedatabase_namecollection_name方法,以确定用于持久化的客户端、数据库和集合名称。

Band.client_name
# => :default
Band.database_name
# => "mongoid"
Band.collection_name
# => :bands

在某些情况下,您可能希望将文档持久化到默认值之外的不同来源,或者使用与默认值不同的选项。Mongoid为此也提供了运行时支持,以及基于每个模型的支撑。

在单个模型级别上,您可以指定存储到自定义集合名称、不同的数据库或不同的客户端。以下示例将默认将 Band 类存储在名为 "artists" 的集合中,该集合位于名为 "music" 的数据库中,使用名为 "analytics" 的客户端。

请注意,提供给 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传递的选项。为了确保此客户端被关闭并释放其相关资源,必须很好地定义此客户端可以使用的范围。

如果您想在运行时切换所有操作的持久化上下文,但不想在代码中到处使用with,Mongoid提供在客户端和数据库级别全局执行此操作的能力。为此提供的方法是Mongoid.override_clientMongoid.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

在上面的示例中,所有持久化操作都将存储在替代数据库中,直到此线程上的所有剩余操作。这就是为什么在请求之后将覆盖设置回nil的原因 - 它确保后续请求(没有本地参数)使用默认选项。

持久化上下文适用于读取和写入操作。例如,可以按照以下方式执行辅助读取

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覆盖集合的:读取或:写入选项

collection_w_0 = Band.collection.with(write: { w: 0 })
collection_w_0[:artists].find(...)

返回

映射/减少