フィールドの定義
項目一覧
- フィールド型
- 型なしフィールド
- フィールドタイプ: StringMongoDB
- フィールドタイプ: シンボル
- フィールドタイプ: ハッシュ
- フィールドタイプ: 時間
- フィールドタイプ: 日付
- フィールド型: DateTime
- フィールドタイプ: 正規表現
- GeoDecimal フィールド
- クラスの代わりにシンボルまたは string を使用
- フィールドのデフォルト値の指定
- ストレージ フィールド名の指定
- フィールド エイリアス
- 予約名
- フィールドの再定義
- カスタム ID
- キャストできない値
- フィールドの動作をカスタマイズする
- カスタム ゲッターとセッター
- カスタムフィールドタイプ
- カスタム フィールド オプション
- 動的フィールド
- フィールド名内の特殊文字
- ローカライズされたフィールド
-
:present
フィールド オプションをローカライズ - フォールバック
- クエリ
- インデックスの作成
- 読み取り専用属性
- タイムスタンプ フィールド
- ドット/ピリオド(
.
)とドル記号($
)を含むフィールド名
フィールド型
MongoDBは BSON typesを使用して基礎となるドキュメント データを保存し、Mongoid はアプリケーションでの実行時にBSON typesをRuby型に変換します。 たとえば、 type: :float
で定義されたフィールドは Ruby Float
クラスのインメモリを使用し、 BSON double
型としてデータベースに永続化します。
フィールドタイプの定義は、クエリを構築し、データベースからフィールドを検索/書き込みするときの Mongoid の動作を決定します。 具体的な説明は以下の通りです。
実行時にフィールドに値を割り当てると、値は指定された型に変換されます。
MongoDB にデータを永続化する場合、データは適切なタイプで送信され、MongoDB 内または他のツールによるより豊富なデータ操作が可能になります。
ドキュメントをクエリする場合、クエリ パラメータは指定された型に変換されてから MongoDB に送信されます。
データベースからドキュメントを検索する際、フィールド値は指定された型に変換されます。
モデル クラスでフィールド定義を変更しても、MongoDB にすでに保存されているデータは変更されません。 既存のドキュメントのフィールドのタイプまたは内容を更新するには、フィールドをデータベースに再保存する必要があります。 Mongoid はモデルのどの属性を追跡し、変更されたもののみを保存するため、保存された値を変更せずに既存のフィールドのタイプを変更するときに、フィールド値を明示的に書き込む必要がある場合があることに注意してください。
アプリケーション内の人物をモデル化するための単純なクラスを検討してください。 人の名前、名前、日付、誕生日、重みがある可能性があります。 field
マイクロを使用して、人物にこれらの属性を定義できます。
class Person include Mongoid::Document field :name, type: String field :date_of_birth, type: Date field :weight, type: Float end
フィールドの有効な型は次のとおりです。
Array
BSON::Binary
Mongoid::Boolean
は、Mongoid::Document
を含むクラスのスコープ内で単純にBoolean
として指定できます。Float
Integer
BSON::ObjectId
Range
Set
String
Mongoid::StringedSymbol 。これは、
Mongoid::Document
を含むクラスの範囲内で単純にStringifiedSymbol
として指定できます。ActiveSupport::TimeWithZone
Mongoid は、string "Boolean"
をMongoid::Boolean
クラスのエイリアスとして認識します。
カスタム フィールド タイプを定義するには、以下の「カスタム フィールド タイプ 」を参照してください。
注意
フィールドタイプとしてBSON::Int64
型とBSON::Int32
型を使用することはサポートされていません。 これらの型をデータベースに保存すると期待どおりに機能しますが、クエリするとRubyの Integer
型が返されます。 BSON::Decimal128
型のフィールドをクエリすると、BSON <=4 ではBSON::Decimal128
型の値と BSON 5+ ではBigDecimal
型の値が返されます。
型なしフィールド
フィールドに型を指定しない場合は、 Object
型を指定するのと同じです。 このようなフィールドは型指定されていません。
class Product include Mongoid::Document field :properties # Equivalent to: field :properties, type: Object end
型指定されていないフィールドには、BSON に直接シリアル化可能な任意の型の値を保存できます。 これは、フィールドに異なる型の値が含まれる可能性がある場合(バリアント型フィールド)、または値の型が事前に不明な場合に便利です。
product = Product.new(properties: "color=white,size=large") product.properties # => "color=white,size=large" product = Product.new(properties: {color: "white", size: "large"}) product.properties # => {:color=>"white", :size=>"large"}
フィールドに値が割り当てられている場合、Mongoid は引き続き mongoization を実行しますが、mongoization ロジックには フィールド型ではなく、値の クラスが使用されます。
product = Product.new(properties: 0..10) product.properties # The range 0..10, mongoized: # => {"min"=>0, "max"=>10}
データベースからデータを読み取る場合、Mongoid は型指定されていないフィールドで型変換を実行しません。 このため、BSON シリアル化可能な任意の値を型なしのフィールドに書き込むことは可能ですが、データベースの読み取り側で特別な処理を必要とする値は、通常、型なしのフィールドでは正しく機能しません。 Mongoid でサポートされているフィールド型のうち、次の型の値は型なしフィールドに保存しないでください。
Date
(値はTime
として返されます)DateTime
(値はTime
として返されます)Range
(値はHash
として返されます)
フィールドタイプ: StringMongoDB
StringifiedSymbol
フィールド型は、Ruby アプリケーションにシンボルとして公開する値を保存するための推奨フィールド型です。 Symbol
フィールド型を使用する場合、Mongoid はデフォルトで値を BSON シンボルとして保存します。 BSON シンボル タイプの詳細については、こちらを参照してください。 ただし、BSON シンボル型は非推奨であり、ネイティブのシンボル型がないプログラミング言語では処理が困難であるため、 StringifiedSymbol
型では他のドライバーとの相互運用性を確保しつつシンボルを使用できます。 StringifiedSymbol
型は、データベース上のすべてのデータを string として保存し、値をシンボルとしてアプリケーションに公開します。
の使用例を以下に示します。
class Post include Mongoid::Document field :status, type: StringifiedSymbol end post = Post.new(status: :hello) # status is stored as "hello" on the database, but returned as a Symbol post.status # => :hello # String values can be assigned also: post = Post.new(status: "hello") # status is stored as "hello" on the database, but returned as a Symbol post.status # => :hello
すべての文字列以外の値はデータベースに送信される際に文字列化され( to_s
経由)、すべての値はアプリケーションに返されるときにシンボルに変換されます。 整数や配列など、記号に直接変換できない値は、アプリケーションに返される前に、まず string に変換され、次に記号に変換されます。
たとえば、整数をstatus
に設定する場合は次のようになります。
post = Post.new(status: 42) post.status # => :"42"
BSON シンボルを含むフィールドにStringifiedSymbol
型が適用されている場合、次回の保存時に値は BSON シンボルではなく string として保存されます。 これにより、データベースに文字列または BSON シンボルのいずれかを現在保存しているフィールドからStringifiedSymbol
フィールドタイプへの透過的な遅延移行が可能になります。
フィールドタイプ: シンボル
新しいアプリケーションでは、データベースに Ruby シンボルを保存するためにStringizedSymbol フィールド タイプを使用する必要があります。 StringifiedSymbol
フィールド型は他のアプリケーションやプログラミング言語との最大の互換性を提供し、すべての状況で同じ動作をします。
Mongoid は、Ruby シンボルを BSON シンボルに直列化するための非推奨のSymbol
フィールド型も提供します。 BSON 仕様では BSON シンボルタイプが非推奨になったため、 bson
gem は単独で使用すると Ruby シンボルを BSON string に直列化します。 ただし、古いデータセットとの下位互換性を維持するために、 mongo
gem はこの動作をオーバーライドして、Ruby シンボルを BSON シンボルとして直列化します。 これは、フィールドとして BSON シンボルを含むドキュメントのクエリを指定できるようにするために必要です。
デフォルトの動作をオーバーライドし、シンボル値を string としてエンコードするようにmongo
gem(および Mongoid も)を構成するには、次のコード スニペットをプロジェクトに含めます。
class Symbol def bson_type BSON::String::BSON_TYPE end end
フィールドタイプ: ハッシュ
ハッシュ 型のフィールドを使用する場合は、 MongoDBの正規キー名に依存しないように注意してください。そうしないと、値が正しく保存されません。
class Person include Mongoid::Document field :first_name field :url, type: Hash # will update the fields properly and save the values def set_vals self.first_name = 'Daniel' self.url = {'home_page' => 'http://www.homepage.com'} save end # all data will fail to save due to the illegal hash key def set_vals_fail self.first_name = 'Daniel' self.url = {'home.page' => 'http://www.homepage.com'} save end end
フィールドタイプ: 時間
Time
フィールドは、 に構成されたタイムゾーンにTime
インスタンスとして値を保存します。
Date
とDateTime
インスタンスは、 Time
フィールドに割り当てられるとTime
インスタンスに変換されます。
class Voter include Mongoid::Document field :registered_at, type: Time end Voter.new(registered_at: Date.today) # => #<Voter _id: 5fdd80392c97a618f07ba344, registered_at: 2020-12-18 05:00:00 UTC>
上記の例では、アプリケーションが UTC 時間を使用するように構成されていないため、値はローカル時間の今日の開始として解釈されました。
注意
データベースにTime
フィールドの string 値が含まれている場合、Mongoid はTime.parse
を使用して string 値を解析します。これにより、タイムゾーンのない値はローカル時間であると見なされます。
フィールドタイプ: 日付
Mongoid では、 Date
フィールドに複数のタイプの値を割り当てることができます。
Date
- 指定された日付はそのまま保存されます。Time
、DateTime
、ActiveSupport::TimeWithZone
- 値の日付コンポーネントは値のタイムゾーンで取得されます。String
- string で指定された日付が使用されます。Integer
、Float
-値は、構成されたタイムゾーンに変換される UTC タイムスタンプとして扱われ(Mongoid.use_utc
はこの変換に影響しないことに注意してください)、日付は結果の時間から取得されます。
つまり、 値で日付が指定されている場合は、その日付が最初に構成されたタイムゾーンに変換されることなく使用されます。
日付と時刻から日付への変換が失われるため(時間コンポーネントが破棄される)、特にアプリケーションが異なるタイムゾーンの時間で動作する場合は、 String
、 Time
、 DateTime
オブジェクトをDate
に明示的に変換することをお勧めします。型Date
フィールドに値を割り当てる前に、 オブジェクトを します。
注意
データベースにDate
フィールドの string 値が含まれている場合、Mongoid はTime.parse
を使用して string 値を解析し、結果のTime
オブジェクトの時間部分を破棄し、日付部分を使用します。 Time.parse
では、タイムゾーンのない値はローカル時間であると見なされます。
フィールド型: DateTime
MongoDB はすべての時間を UTC タイムスタンプとして保存します。 DateTime
フィールドに値を割り当てる場合、またはDateTime
フィールドをクエリする場合、Mongoid は値で渡された値を UTC Time
に変換してから MongoDB サーバーに送信します。
Time
、 ActiveSupport::TimeWithZone
、 DateTime
オブジェクトはタイムゾーン情報を埋め込み、永続化された値は指定された時間における UTC 単位の です。 値が取得されるとき、返されるタイムゾーンは構成されたタイムゾーン設定によって定義されます。
class Ticket include Mongoid::Document field :opened_at, type: DateTime end Time.zone = 'Berlin' ticket = Ticket.create!(opened_at: '2018-02-18 07:00:08 -0500') ticket.opened_at # => Sun, 18 Feb 2018 13:00:08 +0100 ticket # => #<Ticket _id: 5c13d4b9026d7c4e7870bb2f, opened_at: 2018-02-18 12:00:08 UTC> Time.zone = 'America/New_York' ticket.opened_at # => Sun, 18 Feb 2018 07:00:08 -0500 Mongoid.use_utc = true ticket.opened_at # => Sun, 18 Feb 2018 12:00:08 +0000
Mongoid は、 DateTime
への整数と浮動小数点数のキャストもサポートしています。 その場合、整数または浮動小数点数は Unix タイムスタンプ(UTC)であると想定されます。
ticket.opened_at = 1544803974 ticket.opened_at # => Fri, 14 Dec 2018 16:12:54 +0000
string がDateTime
フィールド値として使用される場合、動作は、string にタイムゾーンが含まれているかどうかによって異なります。 タイムゾーンが指定されていない場合は、デフォルトの Mongoid タイムゾーンが使用されます。
Time.zone = 'America/New_York' ticket.opened_at = 'Mar 4, 2018 10:00:00' ticket.opened_at # => Sun, 04 Mar 2018 15:00:00 +0000
タイムゾーンが指定されている場合は、それが尊重されます。
ticket.opened_at = 'Mar 4, 2018 10:00:00 +01:00' ticket.opened_at # => Sun, 04 Mar 2018 09:00:00 +0000
注意
データベースにDateTime
フィールドの string 値が含まれている場合、Mongoid はTime.parse
を使用して string 値を解析します。これにより、タイムゾーンのない値はローカル時間であると見なされます。
フィールドタイプ: 正規表現
MongoDB は、ドキュメントへの正規表現の保存と、正規表現を使用したクエリをサポートしています。 MongoDB は Perl 互換正規表現(PCRE) を使用していることに注意してください と Ruby は Onigmo を使用しています は、 Atlas の正規表現エンジン であり、 。これら 2 つの正規表現の実装は通常同等の機能を提供しますが、構文の重要な違いがいくつかあります。
フィールドが 正規表現 型であると宣言されると、Mongoid は Ruby 正規表現を BSON 正規表現に変換し、その結果を MongoDB に保存します。 データベースからフィールドを取得すると、 BSON::Regexp::Raw
インスタンスが生成されます。
class Token include Mongoid::Document field :pattern, type: Regexp end token = Token.create!(pattern: /hello.world/m) token.pattern # => /hello.world/m token.reload token.pattern # => #<BSON::Regexp::Raw:0x0000555f505e4a20 @pattern="hello.world", @options="ms">
Ruby の正規表現を取得するには、 BSON::Regexp::Raw
で#compile
メソッドを使用します。
token.pattern.compile # => /hello.world/m
正規表現が最初は Ruby のものではなかった場合、 で#compile
を呼び出すと、異なる正規表現が生成される可能性があることに注意してください。 たとえば、次の例では、"hello" で終わる string を一致させる PCRE です。
BSON::Regexp::Raw.new('hello$', 's') # => #<BSON::Regexp::Raw:0x0000555f51441640 @pattern="hello$", @options="s">
この正規表現をコンパイルすると、改行の前に "hello" を含む文字列と、"hello" で終わる文字列に一致する Ruby 正規表現が生成されます。
BSON::Regexp::Raw.new('hello$', 's').compile =~ "hello\nworld" # => 0
これは、 $
の意味が PCRE と Ruby の正規表現で異なるためです。
GeoDecimal フィールド
BigDecimal
フィールド型は、高精度の数値を保存するために使用されます。
BigDecimal
フィールドタイプは、 Mongoid.map_big_decimal_to_decimal128
グローバル構成オプションの値に応じて、データベースに値を 2 つの異なる方法で保存します。 このフラグが false(デフォルト)に設定されている場合、 BigDecimal
フィールドは string として保存され、それ以外の場合はBSON::Decimal128
として保存されます。
BigDecimal
フィールド型は、 BSON::Decimal128
との間で変換する際にいくつかの制限があります。
BSON::Decimal128
は範囲と精度が制限されていますが、BigDecimal
は範囲と精度の点で制限がありません。BSON::Decimal128
の最大値は約10^6145
、最小値は約-10^6145
で、精度は最大 34 ビットです。BSON::Decimal128
に収まらない値を保存する場合は、BSON::Decimal128
ではなく string として保存することをお勧めします。 そのためには、Mongoid.map_big_decimal_to_decimal128
をfalse
に設定する必要があります。BSON::Decimal128
に収まらない値を 1 として保存しようとすると、エラーが発生します。BSON::Decimal128
は符号付きNaN
値を受け入れることができますが、BigDecimal
は受け入れません。BigDecimal
フィールドタイプを使用して符号付きNaN
値をデータベースから検索すると、NaN
は符号なしになります。BSON::Decimal128
データベースに保存されると、後続のゼロが保持されます。 ただし、BigDecimal
では後続のゼロは保持されないため、BigDecimal
フィールド型を使用してBSON::Decimal128
値を取得すると精度が失われる可能性があります。
型のないフィールド(つまり、動的に型指定されたフィールド)にBigDecimal
を保存し、 Mongoid.map_big_decimal_to_decimal128
がfalse
である場合には、追加の警告があります。 この場合、 BigDecimal
は string として保存され、動的フィールドが使用されているため、 BigDecimal
を使用してそのフィールドをクエリしても、 BigDecimal
の string は見つかりません。これは、クエリがBigDecimal
。 その string をクエリするには、 BigDecimal
をまずto_s
で string に変換する必要があります。 フィールドのタイプがBigDecimal
である場合、これは問題にならないことに注意してください。
BigDecimal
を完全に使用しないようにするには、フィールドタイプをBSON::Decimal128
に設定します。 これにより、後続のゼロと符号付きNaN
値を追跡できます。
decimal128
BigDecimal
ベースの フィールドへの移行
Mongoid の将来のメジャー バージョンでは、 Mongoid.map_big_decimal_to_decimal128
グローバル構成オプションはデフォルトでtrue
になります。 このフラグをオンにすると、クエリ内のBigDecimal
値はデータベースにすでに保存されている文字列と一致しなくなります。は、データベース内のdecimal128
値にのみ一致します。 文字列でサポートされているBigDecimal
フィールドがある場合は、次の 3 つのオプションがあります。
Mongoid.map_big_decimal_to_decimal128
グローバル構成オプションをfalse
に設定しても、BigDecimal
値を string として引き続き保存できます。 フィールドの数値に基づいてクエリや集計を実行できるなど、BigDecimal
の値をdecimal128
として保存する利点をスローしていることに注意してください。Mongoid.map_big_decimal_to_decimal128
グローバル構成オプションはtrue
に設定でき、そのフィールドのすべての値を文字列からデータベース内でdecimal128
値に変換できます。 グローバル構成オプション を true に設定する前に、この変換を行う必要があります。 これを実現するクエリの例は次のとおりです。db.bands.updateMany({ "field": { "$exists": true } }, [ { "$set": { "field": { "$toDecimal": "$field" } } } ]) このクエリは、指定されたフィールドを持つすべてのドキュメントを更新し、そのフィールドを対応する
decimal128
値に設定します。 このクエリは MongoDB 4.2+ でのみ機能することに注意してください。Mongoid.map_big_decimal_to_decimal128
グローバル構成オプションはtrue
に設定でき、そのフィールドには文字列とdecimal128
値の両方を指定できます。 これにより、今後はdecimal128
の値のみがデータベースに挿入され、更新されます。decimal128
値のみを使用する完全な利点はまだ得られませんが、古い string 値がdecimal128
に更新され、新しいdecimal128
値が追加されるため、データセットはすべてのdecimal128
値への移行が遅くなります。 。 この設定でも、次のようにBigDecimal
値をクエリできます。Mongoid.map_big_decimal_to_decimal128 = true big_decimal = BigDecimal('2E9') Band.in(sales: [big_decimal, big_decimal.to_s]).to_a このクエリは、
decimal128
値またはその値に一致する string であるすべての値を検索します。
クラスの代わりにシンボルまたは string を使用
Mongoid では、クラスの代わりにシンボルまたは string を使用してフィールドのタイプを指定できます。以下に例を示します。
class Order include Mongoid::Document field :state, type: :integer # Equivalent to: field :state, type: "integer" # Equivalent to: field :state, type: Integer end
この方法では、シンボルまたは string を使用して、以下にリストする標準のフィールドタイプのみを指定できます。 Mongoid は、次の展開を認識します。
:array
=>Array
:big_decimal
=>BigDecimal
:binary
=>BSON::Binary
:boolean
=>Mongoid::Boolean
:date
=>Date
:date_time
=>DateTime
:float
=>Float
:hash
=>Hash
:integer
=>Integer
:object_id
=>BSON::ObjectId
:range
=>Range
:regexp
=>Regexp
:set
=>Set
:string
=>String
:stringified_symbol
=>StringifiedSymbol
:symbol
=>Symbol
:time
=>Time
フィールドのデフォルト値の指定
フィールドにはデフォルト値を設定できます。 デフォルト値は次の例のように固定できます。
class Order include Mongoid::Document field :state, type: String, default: 'created' end
デフォルト値はProc
として指定することもできます。
class Order include Mongoid::Document field :fulfill_by, type: Time, default: ->{ Time.now + 3.days } end
注意
Proc
インスタンスではないデフォルト値はクラスのロード時に評価されます。つまり、次の 2 つの定義は等しくありません。
field :submitted_at, type: Time, default: Time.now field :submitted_at, type: Time, default: ->{ Time.now }
2 番目の定義が適切な定義である可能性が高いため、送信時刻はドキュメントインスタンス化の時点で現在時刻に設定されます。
ドキュメントの状態に依存するデフォルトを設定するには、操作されているドキュメント インスタンスを評価するProc
インスタンス内でself
を使用します。
field :fulfill_by, type: Time, default: ->{ # Order should be fulfilled in 2 business hours. if (7..8).include?(self.submitted_at.hour) self.submitted_at + 4.hours elsif (9..3).include?(self.submitted_at.hour) self.submitted_at + 2.hours else (self.submitted_at + 1.day).change(hour: 11) end }
デフォルト値をProc
として定義する場合、Mongoid は他のすべての属性が設定され、関連付けが初期化された後にデフォルトを適用します。 他の属性が設定される前にデフォルトを適用するには、 pre_processed: true
フィールド オプションを使用します。
field :fulfill_by, type: Time, default: ->{ Time.now + 3.days }, pre_processed: true
関連付けを介して_id
が正しく設定されるように、 pre_processed: true
オプションも必要です。 Proc
を介して_id
フィールドにカスタム デフォルト値を指定するときにも必要です。
field :_id, type: String, default: -> { 'hello' }, pre_processed: true
ストレージ フィールド名の指定
スキーマレス データベースを持つ利点の 1 つは、MongoDB がすべてのフィールド情報を各ドキュメントとともに保存する必要があるため、RAM とディスク上の多くのストレージ領域を消費することです。 これを制限する一般的なパターンは、アプリケーション内のドメインを表現的に維持しながら、フィールドを少数の文字数にエイリアスすることです。 Mongoid を使用すると、変換を実行中に、ゲッター、セッター、基準内の長い名前でドメイン内のフィールドを参照できます。
class Band include Mongoid::Document field :n, as: :name, type: String end band = Band.new(name: "Placebo") band.attributes # { "n" => "Placebo" } criteria = Band.where(name: "Placebo") criteria.selector # { "n" => "Placebo" }
フィールド エイリアス
フィールド エイリアスを定義することができます。 値は宛先フィールドに保存されますが、宛先フィールドまたはエイリアス フィールドからアクセスできます。
class Band include Mongoid::Document field :name, type: String alias_attribute :n, :name end band = Band.new(n: 'Astral Projection') # => #<Band _id: 5fc1c1ee2c97a64accbeb5e1, name: "Astral Projection"> band.attributes # => {"_id"=>BSON::ObjectId('5fc1c1ee2c97a64accbeb5e1'), "name"=>"Astral Projection"} band.n # => "Astral Projection"
エイリアスは、 unalias_attribute
メソッドを使用してモデル クラスから削除できます。
class Band unalias_attribute :n end
Unaliasing id
unalias_attribute
事前定義されたid
エイリアスを削除するために使用できます。 これは、 フィールドと フィールドに異なる値を保存するのに便利です。id
_id
class Band include Mongoid::Document unalias_attribute :id field :id, type: String end Band.new(id: '42') # => #<Band _id: 5fc1c3f42c97a6590684046c, id: "42">
予約名
Mongoid の予約メソッド名と競合するドキュメントにフィールドを定義しようとすると、エラーが発生します。 予約名のリストは、 Mongoid.destructive_fields
メソッドを呼び出すと取得できます。
フィールドの再定義
デフォルトでは、Mongoid ではモデルのフィールドの再定義が許可されています。 フィールドが再定義されたときにエラーを発生させるには、 duplicate_fields_exception
構成オプションをtrue
に設定します。
オプションが true に設定されている場合、次の例ではエラーが発生します。
class Person include Mongoid::Document field :name field :name, type: String end
フィールドを定義するには、 overwrite: true
オプションを使用します。
class Person include Mongoid::Document field :name field :name, type: String, overwrite: true end
カスタム ID
デフォルトでは、Mongoid はドキュメントの_id
フィールドを定義して、Mongoid によって自動生成されるBSON::ObjectId
値を含めます。
_id
フィールドの定義を置き換えて、 _id
値のタイプを変更したり、別のデフォルト値にすることができます。
class Band include Mongoid::Document field :name, type: String field :_id, type: String, default: ->{ name } end
デフォルトを完全に省略することもできます。
class Band include Mongoid::Document field :_id, type: String end
_id
のデフォルトが省略されており、アプリケーションによって_id
値が提供されていない場合、Mongoid は_id
値なしでドキュメントを永続化します。 この場合、ドキュメントが最上位ドキュメントであれば、サーバーによって_id
値が割り当てられます。ドキュメントが埋め込みドキュメントの場合、 _id
値は割り当てられません。 Mongoid は、ドキュメントが永続化されているときに、割り当てられている場合でも、この値を自動的に取得しません。他の手段を使用して、永続化された値(および完全な永続化ドキュメント)を取得する必要があります。
band = Band.create! => #<Band _id: , > band.id => nil band.reload # raises Mongoid::Errors::DocumentNotFound Band.last => #<Band _id: 5fc681c22c97a6791f324b99, >
埋め込みドキュメントでは、 _id
フィールドを省略する方が一般的です。
Mongoid は、id
のエイリアスとなる_id
フィールドも定義します。id
エイリアスは、必要に応じて削除できます(たとえば、 id
フィールドを使用して_id
とは異なる値を保存するシステムと統合するなど)。
キャストできない値
Mongoid 8 では、Mongoid は の割り当てと「キャストできない」値の読み取りの処理を標準化しました。 値は、フィールドのタイプに強制できない場合、「キャスト不可」と見なされます。 たとえば、配列は整数フィールドに対して「キャストできない」値になります。
キャストできない値の割り当て
キャストできない値の割り当てがデフォルトでnil
を割り当てるように標準化されました。 次の例で考えてみましょう。
class User include Mongoid::Document field :name, type: Integer end User.new(name: [ "hello" ])
配列を整数に強制できないため、整数型のフィールドに配列を割り当てても機能しません。 フィールドにキャストできない値を割り当てると、 nil
が書き込まれます。
user = User.new(name: [ "Mike", "Trout" ]) # => #<User _id: 62b222d43282a47bf73e3264, name: nil>
元のキャストできない値は、フィールド名とともにattributes_before_type_cast
ハッシュに保存されることに注意してください。
user.attributes_before_type_cast["name"] # => ["Mike", "Trout"]
注意
数値フィールドの場合、整数フィールドにはto_i
、浮動小数点数にはto_f
、ビッグデプロイメントにはto_d
を定義するクラスはすべてキャスト可能です。 string は例外であり、string が数値の場合にのみ、対応するto_*
メソッドを呼び出します。 クラスが to_i
のみを定義し、 to_f
ではなくのみを定義し、かつ 、浮動小数点数フィールドに割り当てられている場合、これはキャスト可能ではなく、Mongoid は 2 段階の変換を実行しません(つまり to_i
、次にto_f
)。
キャストできない値の読み取り
データベース内のドキュメントに Mongoid の表現とは異なる型の値が含まれている場合、Mongoid がそれらを正しい型に強制できない場合は、値がnil
に置き換えられます。 データベース内の次のモデルとドキュメントを考慮します。
class User include Mongoid::Document field :name, type: Integer end
{ _id: ..., name: [ "Mike", "Trout" ] }
データベースからこのドキュメントを読み取ると、モデルの名前フィールドにnil
が含まれる結果になります。
User.first.name # => nil
配列のデータベース値は、配列を整数に強制できないため、 属性に保存できません。 元のキャストできない値は、フィールド名とともにattributes_before_type_cast
ハッシュに保存されることに注意してください。
user.attributes_before_type_cast["name"] # => ["Mike", "Trout"]
注意
コンテナ オブジェクトのdemongoize
メソッド( ハッシュ、配列)は、ミューテーションされたコンテナ属性の自動永続性を許可するように変更されていません。 MONGOID-2951 を参照してください このトピックの詳細な説明は、 を参照してください。
フィールドの動作をカスタマイズする
Mongoid には、フィールドの動作をカスタマイズする方法がいくつか用意されています。
カスタム ゲッターとセッター
フィールドの getter と setter をオーバーライドして、アクセスまたは書き込み時に値を変更できます。 ゲッターとセッターは フィールドと同じ名前を使用します。 ゲッターとセッター内でread_attribute
メソッドとwrite_attribute
メソッドを使用して、未加工の属性値を操作します。
たとえば、Mongoid には、フィールドにデフォルト値を書込むための:default
フィールド オプションが用意されています。 アプリケーション内でフィールドのデフォルト値を設定したいが、それを永続化したくない場合は、次のように getter を上書きできます。
class DistanceMeasurement include Mongoid::Document field :value, type: Float field :unit, type: String def unit read_attribute(:unit) || "m" end def to_s "#{value} #{unit}" end end measurement = DistanceMeasurement.new(value: 2) measurement.to_s # => "2.0 m" measurement.attributes # => {"_id"=>BSON::ObjectId('613fa0b0a15d5d61502f3447'), "value"=>2.0}
別の例えとして、空の文字列を nil 値に変換するフィールドは、次のように実装できます。
class DistanceMeasurement include Mongoid::Document field :value, type: Float field :unit, type: String def unit=(value) if value.blank? value = nil end write_attribute(:unit, value) end end measurement = DistanceMeasurement.new(value: 2, unit: "") measurement.attributes # => {"_id"=>BSON::ObjectId('613fa15aa15d5d617216104c'), "value"=>2.0, "unit"=>nil}
カスタムフィールドタイプ
Mongoid でカスタム型を定義し、どのように直列化および逆直列化するかを決定できます。 この例では、新しいフィールドタイプPoint
を定義し、モデル クラスで次のように使用できます。
class Profile include Mongoid::Document field :location, type: Point end
次に、型を表す Ruby クラスを作成します。 このクラスは、MongoDB の直列化と逆直列化に使用されるメソッドを次のように定義する必要があります。
class Point attr_reader :x, :y def initialize(x, y) @x, @y = x, y end # Converts an object of this instance into a database friendly value. # In this example, we store the values in the database as array. def mongoize [ x, y ] end class << self # Takes any possible object and converts it to how it would be # stored in the database. def mongoize(object) case object when Point then object.mongoize when Hash then Point.new(object[:x], object[:y]).mongoize else object end end # Get the object as it was stored in the database, and instantiate # this custom class from it. def demongoize(object) Point.new(object[0], object[1]) end # Converts the object that was supplied to a criteria and converts it # into a query-friendly form. def evolve(object) case object when Point then object.mongoize else object end end end end
インスタンス メソッドmongoize
は、カスタム型オブジェクトのインスタンスを受け取り、それをデータベースに保存する方法の表現に変換します。つまり、MongoDB Ruby ドライバーに渡します。 上記の例では、 Point
オブジェクトをArray
として[ x, y ]
という形式で保存する必要があります。
クラス メソッドmongoize
は インスタンス メソッドと似ていますが、使用可能なすべてのタイプのオブジェクトを入力として取り扱う必要があります。 mongoize
メソッドは、カスタム型のフィールドに対して setter メソッドを呼び出すときに使用されます。
point = Point.new(12, 24) venue = Venue.new(location: point) # This uses the Point#mongoize instance method. venue = Venue.new(location: [ 12, 24 ]) # This uses the Point.mongoize class method.
クラス メソッドdemongoize
はmongoize
の逆を行います。 MongoDB Ruby ドライバーから未加工のオブジェクトを受け取り、カスタム タイプのインスタンスに変換します。 この場合、データベース ドライバーはArray
を返し、それからPoint
をインスタンス化します。 demongoize
メソッドは、カスタム タイプのフィールドの getter を呼び出すときに使用されます。 上記の例では、 demongoize
はPoint.new
を呼び出すため、ゲッターを呼び出すごとにPoint
の新しいインスタンスが生成されます。
Mongoid はデータベースから検索された値に対して常にdemongoize
メソッドを呼び出しますが、アプリケーションは任意の入力でdemongoize
を呼び出す可能性があります。 アプリではdemongoize
メソッドに任意の入力の処理を追加することをお勧めします。 Point
のmongoize メソッドは次のように書き換えることができます。
def demongoize(object) if object.is_a?(Array) && object.length == 2 Point.new(object[0], object[1]) end end
demongoize
は、長さ2の配列が指定された場合にのみ新しいPoint
を作成し、それ以外の場合はnil
を返すことに注意してください。 mongoize
demongoize
メソッドとnil
メソッドはどちらも任意の入力を受け入れるために準備され、カスタム タイプにキャストできない値に対して を返す必要があります。詳細については、「キャストできない値」のセクションを参照してください。
最後に、クラス メソッドevolve
はmongoize
と似ていますが、Mongoid クエリ条件で使用するためにオブジェクトを変換するときに使用されます。
point = Point.new(12, 24) Venue.where(location: point) # This uses Point.evolve
evolve
メソッドも任意の入力を受け入れるために準備する必要がありますが、 メソッドとmongoize
demongoize
メソッドとは異なり、カスタム型にキャストできない値の入力値を返す必要があります。詳細については、「キャストできない値」のセクションを参照してください。
仮想カスタムフィールドタイプ
カスタム フィールドタイプは、ユーザーが表示できる属性値からデータベースに保存されている値への変換を実行する可能性があります。 たとえば、これを使用して、ある列挙から別の列へのマッピングを実装し、アプリケーションにより記述的な値を与え、データベースに保存される値をより圧縮できます。
class ColorMapping MAPPING = { 'black' => 0, 'white' => 1, }.freeze INVERSE_MAPPING = MAPPING.invert.freeze class << self # Takes application-scope value and converts it to how it would be # stored in the database. Converts invalid values to nil. def mongoize(object) MAPPING[object] end # Get the value as it was stored in the database, and convert to # application-scope value. Converts invalid values to nil. def demongoize(object) INVERSE_MAPPING[object] end # Converts the object that was supplied to a criteria and converts it # into a query-friendly form. Returns invalid values as is. def evolve(object) MAPPING.fetch(object, object) end end end class Profile include Mongoid::Document field :color, type: ColorMapping end profile = Profile.new(color: 'white') profile.color # => "white" # Writes 0 to color field profile.save!
カスタム フィールド オプション
モデル クラスが読み込まれたときに動作を拡張するfield
マイクロ関数のカスタム オプションを定義できます。
例として、 フィールドに長さバリデーターを追加する:max_length
オプションを定義します。 まず、初期化プロセスで新しい フィールド オプションを宣言し、そのハンドラー関数を ブロックとして指定します。
# in /config/initializers/mongoid_custom_fields.rb Mongoid::Fields.option :max_length do |model, field, value| model.validates_length_of field.name, maximum: value end
次に、それをモデル クラスを使用します。
class Person include Mongoid::Document field :name, type: String, max_length: 10 end
フィールド定義でオプションが使用されるたびに、オプションの値が false または nil であっても、 ハンドラー関数は呼び出されることに注意してください。
動的フィールド
デフォルトでは、Mongoid ではドキュメントに設定できるすべてのフィールドが、 field
宣言を使用して明示的に定義される必要があります。 Mongoid では、データベースに保存されている任意のハッシュやドキュメントから、その日にフィールドを作成することもサポートされています。 明示的に定義されていないフィールドをモデルが使用する場合、このようなフィールドは動的フィールドと呼ばれます。
動的フィールドを有効にするには、モデルにMongoid::Attributes::Dynamic
モジュールを含めます。
class Person include Mongoid::Document include Mongoid::Attributes::Dynamic end bob = Person.new(name: 'Bob', age: 42) bob.name # => "Bob"
同じモデル クラスでfield
宣言と動的フィールドを使用できます。 field
宣言がある属性はfield
宣言に従って扱われ、残りの属性は動的フィールドとして扱われます。
動的フィールドの属性値は、 write_attribute
を使用して、属性ハッシュをコンストラクターに渡すか、 attributes=
による一括割り当て、 []=
からの一括割り当てを渡して最初に設定する必要があります。または、データベースにすでに存在している必要があります。
# OK bob = Person.new(name: 'Bob') # OK bob = Person.new bob.attributes = {age: 42} # OK bob = Person.new bob['age'] = 42 # Raises NoMethodError: undefined method age= bob = Person.new bob.age = 42 # OK bob = Person.new # OK - string access bob.write_attribute('age', 42) # OK - symbol access bob.write_attribute(:name, 'Bob') # OK, initializes attributes from whatever is in the database bob = Person.find('123')
属性が特定のモデル インスタンスの属性ハッシュに存在しない場合、対応するフィールドのリーダーとライターの両方が定義されておらず、それらを呼び出すとNoMethodError
が発生します。
bob = Person.new bob.attributes = {age: 42} bob.age # => 42 # raises NoMethodError bob.name # raises NoMethodError bob.name = 'Bob' # OK bob['name'] = 'Bob' bob.name # => "Bob"
一括属性アクセス またはread_attribute
を使用して、いつでも属性を読み取ることができます(これは、 動的フィールド を使用していないモデルにも適用されます)。
bob = Person.new(age: 42) # OK - string access bob['name'] # => nil # OK - symbol access bob[:name] # => nil # OK - string access bob['age'] # => 42 # OK - symbol access bob[:age] # => 42 # OK bob.attributes['name'] # => nil # OK bob.attributes['age'] # => 42 # Returns nil - keys are always strings bob.attributes[:age] # => nil # OK bob.read_attribute('name') # => nil # OK bob.read_attribute(:name) # => nil # OK - string access bob.read_attribute('age') # => 42 # OK - symbol access bob.read_attribute(:age) # => 42
注意
read_attribute
メソッドから返される値とattributes
ハッシュに保存されている値はmongoized
値です。
フィールド名内の特殊文字
Mongoid では、動的フィールド名にスペースや句読点を含めることができます。
bob = Person.new('hello world' => 'MDB') bob.send('hello world') # => "MDB" bob.write_attribute("hello%world", 'MDB') bob[:"hello%world"] # => "MDB"
ローカライズされたフィールド
Mongoid は I18 n gem を 介してローカライズされたフィールドをサポートします 。
class Product include Mongoid::Document field :description, type: String, localize: true end
フィールドをlocalize
に渡すことで、Mongoid は カバーの下にフィールドをロケールと値のペアのハッシュとして保存しますが、そのフィールドへの通常のアクセスは string のように動作します。
I18n.default_locale = :en product = Product.new product.description = "Marvelous!" I18n.locale = :de product.description = "Fantastisch!" product.attributes # { "description" => { "en" => "Marvelous!", "de" => "Fantastisch!" }
対応する_translations
メソッドを使用して、一度にすべての翻訳を取得して設定できます。
product.description_translations # { "en" => "Marvelous!", "de" => "Fantastisch!" } product.description_translations = { "en" => "Marvelous!", "de" => "Wunderbar!" }
ローカライズされたフィールドはどのフィールドタイプでも使用できます。 たとえば、通貨との差異には、浮動小数フィールドとともに使用できます。
class Product include Mongoid::Document field :price, type: Float, localize: true field :currency, type: String, localize: true end
この方法でモデルを作成することで、価格を通貨の種類から分離できます。これにより、そのフィールドをクエリまたは集計する際に、価格に数値に関連するすべての機能を使用できます(保存された翻訳ハッシュにインデックスを作成する場合を除く) 。 このモデルのインスタンスは、次のように作成できます。
product = Product.new I18n.locale = :en product.price = 1.00 product.currency = "$" I18n.locale = :he product.price = 3.24 product.currency = "₪" product.attributes # => { "price" => { "en" => 1.0, "he" => 3.24 }, "currency" => { "en" => "$", "he" => "₪" } }
:present
フィールド オプションをローカライズする
Mongoid では、ローカライズされたフィールドの作成時に:present
オプションがサポートされています。
class Product include Mongoid::Document field :description, localize: :present end
このオプションは自動的にblank
値( blank?
メソッドに対して true を返すもの)を_translations
ハッシュから
I18n.default_locale = :en product = Product.new product.description = "Marvelous!" I18n.locale = :de product.description = "Fantastisch!" product.description_translations # { "en" => "Marvelous!", "de" => "Fantastisch!" } product.description = "" product.description_translations # { "en" => "Marvelous!" }
:de
ロケールに空のstringが書き込まれると、空の文字列 が書き込まれる代わりに、"de"
キーが _translations
ハッシュから削除されstring 。
フォールバック
Mongoid は i18 n フォールバック と統合します 。フォールバックを使用するには、それぞれの機能を明示的に有効にする必要があります。
Rails アプリケーションで、環境内でconfig.i18n.fallbacks
構成設定をtrue
に設定し、フォールバック言語を指定します。
config.i18n.fallbacks = true config.after_initialize do I18n.fallbacks[:de] = [ :en, :es ] end
非 Rails アプリケーションでは、使用している I18n バックエンドに フォールバック モジュールを含め、フォールバック言語を指定します。
require "i18n/backend/fallbacks" I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) I18n.fallbacks[:de] = [ :en, :es ]
フォールバック が有効になっている場合、アクティブな言語に翻訳が存在しない場合は、フォールバック言語で翻訳が検索されます。
product = Product.new I18n.locale = :en product.description = "Marvelous!" I18n.locale = :de product.description # "Marvelous!"
Mongoid は フィールドに:fallbacks
オプションも定義しています。このオプションは、特定のフィールドのフォールバック機能を無効にするために使用できます。
class Product include Mongoid::Document field :description, type: String, localize: true, fallbacks: false end product = Product.new I18n.locale = :en product.description = "Marvelous!" I18n.locale = :de product.description # nil
このオプションのデフォルトはtrue
であることに注意してください。
注意
i18 n1.1 では、フォールバックの動作が 変更されました フォールバック ロケールが提供されていない場合にデフォルト ロケールにフォールバックするのではなく、常にフォールバック ロケールの明示的なリストを必要とする ようにします。
クエリ
Mongoid の条件 API を使用してローカライズされたフィールドをクエリする場合、Mongoid は現在のロケールに一致するように条件を自動的に変更します。
# Match all products with Marvelous as the description. Locale is en. Product.where(description: "Marvelous!") # The resulting MongoDB query filter: { "description.en" : "Marvelous!" }
インデックスの作成
ローカライズされたフィールドを頻繁にクエリする場合は、検索する各ロケールにインデックスを作成する必要があります。
class Product include Mongoid::Document field :description, localize: true index "description.de" => 1 index "description.en" => 1 end
読み取り専用属性
特定の属性を読み取り専用にすることを Mongoid に指示できます。 これにより、これらの属性でドキュメントを作成できるようになりますが、 update_attributes
などの一括更新メソッドを使用すると、それらへの変更は無視されます。
class Band include Mongoid::Document field :name, type: String field :origin, type: String attr_readonly :name, :origin end band = Band.create(name: "Placebo") band.update_attributes(name: "Tool") # Filters out the name change.
読み取り専用属性を単独で明示的に更新または削除しようとすると、 ReadonlyAttribute
例外が発生します。
band.update_attribute(:name, "Tool") # Raises the error. band.remove_attribute(:name) # Raises the error.
セッターを使用した読み取り専用属性への割り当ては無視されます。
b = Band.create!(name: "The Rolling Stones") # => #<Band _id: 6287a3d5d1327a5292535383, name: "The Rolling Stones", origin: nil> b.name = "The Smashing Pumpkins" # => "The Smashing Pumpkins" b.name # => "The Rolling Stones"
bit
やinc
などのアトミック永続演算子を呼び出すと、読み取り専用フィールドの変更が永続化されます。
タイムスタンプ フィールド
Mongoid は、 にタイムスタンプMongoid::Timestamps
created_at
updated_at
モジュールを提供しています。これを含めることで、 フィールドと フィールドの基本的な動作を実現するために含めることができます。
class Person include Mongoid::Document include Mongoid::Timestamps end
また、作成または変更の特定のタイムスタンプのみを選択することもできます。
class Person include Mongoid::Document include Mongoid::Timestamps::Created end class Post include Mongoid::Document include Mongoid::Timestamps::Updated end
特定の呼び出しのタイムスタンプをオフにする場合は、 タイムレス メソッドを使用します。
person.timeless.save Person.timeless.create!
スペースを節約するために、エイリアスを持つ短いタイムスタンプ フィールドが必要な場合は、モジュールの短いバージョンを含めることができます。
class Band include Mongoid::Document include Mongoid::Timestamps::Short # For c_at and u_at. end class Band include Mongoid::Document include Mongoid::Timestamps::Created::Short # For c_at only. end class Band include Mongoid::Document include Mongoid::Timestamps::Updated::Short # For u_at only. end
ドット/ピリオド(.
)とドル記号( )を含むフィールド名$
フィールド名にドットまたはピリオド( .
)を使用し、フィールド名をドル記号( $
)で始めることは推奨されません。Mongoid では、これらのフィールドに保存されているドキュメントの取得と操作のサポートが限定的です。
Mongoid と MongoDB クエリ言語(MQL)の両方で通常、埋め込みドキュメントを走査するフィールドパス内のフィールド名と、ドル記号( $
)で始まる単語を演算子として区切るには、ドット/ピリオド( .
)を使用します。 MongoDB では、他のソフトウェアとの相互運用性のために、ドットを含むフィールド名とドル記号で始まるフィールド名を限定的にサポートしていますが、このサポートは特定の演算子(例: getField 、 setField )およびクエリと更新の両方に 集計パイプライン の使用を必要とする場合は、アプリケーションはフィールド名にドットを使用したり、フィールド名をドル記号で開始したりすることを可能な限り避けなければなりません。
Mongoid バージョン 8 以降、ドル記号で始まり、ドットやピリオドを含むフィールドにユーザーがアクセスできるようになりました。 次のようにsend
メソッドを使用してアクセスできます。
class User include Mongoid::Document field :"first.last", type: String field :"$_amount", type: Integer end user = User.first user.send(:"first.last") # => Mike.Trout user.send(:"$_amount") # => 42650000
これらのフィールドには、 read_attribute
を使用することもできます。
user.read_attribute("first.last") # => Mike.Trout
サーバーの制限により、ドットとドルを含むフィールドの更新と置換には特別な演算子を使用する必要があります。 このため、これらのフィールドでセッターを呼び出すことは禁止されており、エラーが発生します。
class User include Mongoid::Document field :"first.last", type: String field :"$_amount", type: Integer end user = User.new user.send(:"first.last=", "Shohei.Ohtani") # raises a InvalidDotDollarAssignment error user.send(:"$_amount=", 8500000) # raises a InvalidDotDollarAssignment error