Docs Menu
Docs Home
/ / /
Mongoid
/

フィールドの定義

項目一覧

  • フィールド型
  • 型なしフィールド
  • フィールドタイプ: StringMongoDB
  • フィールドタイプ: シンボル
  • フィールドタイプ: ハッシュ
  • フィールドタイプ: 時間
  • フィールドタイプ: 日付
  • フィールド型: DateTime
  • フィールドタイプ: 正規表現
  • GeoDecimal フィールド
  • クラスの代わりにシンボルまたは string を使用
  • フィールドのデフォルト値の指定
  • ストレージ フィールド名の指定
  • フィールド エイリアス
  • 予約名
  • フィールドの再定義
  • カスタム ID
  • キャストできない値
  • フィールドの動作をカスタマイズする
  • カスタム ゲッターとセッター
  • カスタムフィールドタイプ
  • カスタム フィールド オプション
  • 動的フィールド
  • フィールド名内の特殊文字
  • ローカライズされたフィールド
  • :presentフィールド オプションをローカライズ
  • フォールバック
  • クエリ
  • インデックスの作成
  • 読み取り専用属性
  • タイムスタンプ フィールド
  • ドット/ピリオド( . )とドル記号( $ )を含むフィールド名

MongoDBは BSON typesを使用して基礎となるドキュメント データを保存し、Mongoid はアプリケーションでの実行時にBSON typesをRuby型に変換します。 たとえば、 type: :floatで定義されたフィールドは Ruby Floatクラスのインメモリを使用し、 BSON double型としてデータベースに永続化します。

フィールドタイプの定義は、クエリを構築し、データベースからフィールドを検索/書き込みするときの Mongoid の動作を決定します。 具体的な説明は以下の通りです。

  1. 実行時にフィールドに値を割り当てると、値は指定された型に変換されます。

  2. MongoDB にデータを永続化する場合、データは適切なタイプで送信され、MongoDB 内または他のツールによるより豊富なデータ操作が可能になります。

  3. ドキュメントをクエリする場合、クエリ パラメータは指定された型に変換されてから MongoDB に送信されます。

  4. データベースからドキュメントを検索する際、フィールド値は指定された型に変換されます。

モデル クラスでフィールド定義を変更しても、MongoDB にすでに保存されているデータは変更されません。 既存のドキュメントのフィールドのタイプまたは内容を更新するには、フィールドをデータベースに再保存する必要があります。 Mongoid はモデルのどの属性を追跡し、変更されたもののみを保存するため、保存された値を変更せずに既存のフィールドのタイプを変更するときに、フィールド値を明示的に書き込む必要がある場合があることに注意してください。

アプリケーション内の人物をモデル化するための単純なクラスを検討してください。 人の名前、名前、日付、誕生日、重みがある可能性があります。 fieldマイクロを使用して、人物にこれらの属性を定義できます。

class Person
include Mongoid::Document
field :name, type: String
field :date_of_birth, type: Date
field :weight, type: Float
end

フィールドの有効な型は次のとおりです。

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として返されます)

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インスタンスとして値を保存します。

DateDateTimeインスタンスは、 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 - 指定された日付はそのまま保存されます。

  • TimeDateTimeActiveSupport::TimeWithZone - 値の日付コンポーネントは値のタイムゾーンで取得されます。

  • String - string で指定された日付が使用されます。

  • IntegerFloat -値は、構成されたタイムゾーンに変換される UTC タイムスタンプとして扱われ( Mongoid.use_utcはこの変換に影響しないことに注意してください)、日付は結果の時間から取得されます。

つまり、 値で日付が指定されている場合は、その日付が最初に構成されたタイムゾーンに変換されることなく使用されます。

日付と時刻から日付への変換が失われるため(時間コンポーネントが破棄される)、特にアプリケーションが異なるタイムゾーンの時間で動作する場合は、 StringTimeDateTimeオブジェクトをDateに明示的に変換することをお勧めします。型Date フィールドに値を割り当てる前に、 オブジェクトを します。

注意

データベースにDateフィールドの string 値が含まれている場合、Mongoid はTime.parseを使用して string 値を解析し、結果のTimeオブジェクトの時間部分を破棄し、日付部分を使用します。 Time.parseでは、タイムゾーンのない値はローカル時間であると見なされます。

MongoDB はすべての時間を UTC タイムスタンプとして保存します。 DateTimeフィールドに値を割り当てる場合、またはDateTimeフィールドをクエリする場合、Mongoid は値で渡された値を UTC Timeに変換してから MongoDB サーバーに送信します。

TimeActiveSupport::TimeWithZoneDateTimeオブジェクトはタイムゾーン情報を埋め込み、永続化された値は指定された時間における 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 の正規表現で異なるためです。

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_decimal128falseに設定する必要があります。 BSON::Decimal128に収まらない値を 1 として保存しようとすると、エラーが発生します。

  • BSON::Decimal128 は符号付きNaN値を受け入れることができますが、 BigDecimalは受け入れません。 BigDecimalフィールドタイプを使用して符号付きNaN値をデータベースから検索すると、 NaNは符号なしになります。

  • BSON::Decimal128 データベースに保存されると、後続のゼロが保持されます。 ただし、 BigDecimalでは後続のゼロは保持されないため、 BigDecimalフィールド型を使用してBSON::Decimal128値を取得すると精度が失われる可能性があります。

型のないフィールド(つまり、動的に型指定されたフィールド)にBigDecimalを保存し、 Mongoid.map_big_decimal_to_decimal128falseである場合には、追加の警告があります。 この場合、 BigDecimalは string として保存され、動的フィールドが使用されているため、 BigDecimalを使用してそのフィールドをクエリしても、 BigDecimalの string は見つかりません。これは、クエリがBigDecimal 。 その string をクエリするには、 BigDecimalをまずto_sで string に変換する必要があります。 フィールドのタイプがBigDecimalである場合、これは問題にならないことに注意してください。

BigDecimalを完全に使用しないようにするには、フィールドタイプをBSON::Decimal128に設定します。 これにより、後続のゼロと符号付きNaN値を追跡できます。

Mongoid の将来のメジャー バージョンでは、 Mongoid.map_big_decimal_to_decimal128グローバル構成オプションはデフォルトでtrueになります。 このフラグをオンにすると、クエリ内のBigDecimal値はデータベースにすでに保存されている文字列と一致しなくなります。は、データベース内のdecimal128値にのみ一致します。 文字列でサポートされているBigDecimalフィールドがある場合は、次の 3 つのオプションがあります。

  1. Mongoid.map_big_decimal_to_decimal128グローバル構成オプションをfalseに設定しても、 BigDecimal値を string として引き続き保存できます。 フィールドの数値に基づいてクエリや集計を実行できるなど、 BigDecimalの値をdecimal128として保存する利点をスローしていることに注意してください。

  2. Mongoid.map_big_decimal_to_decimal128グローバル構成オプションはtrueに設定でき、そのフィールドのすべての値を文字列からデータベース内でdecimal128値に変換できます。 グローバル構成オプション を true に設定する前に、この変換を行う必要があります。 これを実現するクエリの例は次のとおりです。

    db.bands.updateMany({
    "field": { "$exists": true }
    }, [
    {
    "$set": {
    "field": { "$toDecimal": "$field" }
    }
    }
    ])

    このクエリは、指定されたフィールドを持つすべてのドキュメントを更新し、そのフィールドを対応するdecimal128値に設定します。 このクエリは MongoDB 4.2+ でのみ機能することに注意してください。

  3. 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 であるすべての値を検索します。

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

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

デフォルトでは、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.

クラス メソッドdemongoizemongoizeの逆を行います。 MongoDB Ruby ドライバーから未加工のオブジェクトを受け取り、カスタム タイプのインスタンスに変換します。 この場合、データベース ドライバーはArrayを返し、それからPointをインスタンス化します。 demongoizeメソッドは、カスタム タイプのフィールドの getter を呼び出すときに使用されます。 上記の例では、 demongoizePoint.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を返すことに注意してください。 mongoizedemongoizeメソッドとnil メソッドはどちらも任意の入力を受け入れるために準備され、カスタム タイプにキャストできない値に対して を返す必要があります。詳細については、「キャストできない値」のセクションを参照してください。

最後に、クラス メソッドevolvemongoizeと似ていますが、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" => "₪" } }

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"

bitincなどのアトミック永続演算子を呼び出すと、読み取り専用フィールドの変更が永続化されます。

Mongoid は、 にタイムスタンプMongoid::Timestamps created_atupdated_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 では、他のソフトウェアとの相互運用性のために、ドットを含むフィールド名とドル記号で始まるフィールド名を限定的にサポートしていますが、このサポートは特定の演算子(例: getFieldsetField )およびクエリと更新の両方に 集計パイプライン の使用を必要とする場合は、アプリケーションはフィールド名にドットを使用したり、フィールド名をドル記号で開始したりすることを可能な限り避けなければなりません。

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

戻る

スキーマ構成