クエリ
項目一覧
- 条件構文
- フィールド構文
- MQL 構文
- シンボル演算子構文
- フィールド
- 定義済みフィールドのクエリ
- Raw Values のクエリ
- フィールド エイリアス
- 埋め込みドキュメント
- 論理演算
- 演算子の組み合わせ
and
動作any_of
動作none_of
動作not
動作- 増分クエリ構築
- 合併戦略
- サポートされている演算子メソッド
- 演算子値の拡張
- クエリメソッド
- elem_match
- プロジェクション
only
without
- 順序
- ページ分割
limit
skip
batch_size
- 検索方法
_id
- 追加のクエリメソッド
- 積載量
- 正規表現
- フィールドの条件
- スコープ設定
- 名前付きスコープ
- デフォルトのスコープ
- ランタイムのデフォルトスコープの上書き
- クラスメソッド
- クエリ + 永続性
- クエリ キャッシュ
- クエリキャッシュの有効化
- クエリキャッシュの自動有効化
- クエリキャッシュの手動有効化
- 結果をキャッシュする
#first
- 非同期クエリ
- 非同期クエリ実行の構成
Mongoid は、ActiveRecord に触発された豊富なクエリ DSL を提供します。簡単なクエリは次のようになります。
Band.where(name: "Depeche Mode")
さまざまな Mongoid 機能を活用したより複雑なクエリは次のようになります。
Band. where(:founded.gte => "1980-01-01"). in(name: [ "Tool", "Deftones" ]). union. in(name: [ "Melvins" ])
クエリ メソッドは、MongoDB クエリ言語 (MQL) の連鎖可能で遅延評価されるラッパーである Mongoid::Criteria
オブジェクトを返します。クエリは、結果セットが反復されるときに実行されます。例:
# Construct a Criteria object: Band.where(name: 'Deftones') # => #<Mongoid::Criteria # selector: {"name"=>"Deftones"} # options: {} # class: Band # embedded: false> # Evaluate the query and get matching documents: Band.where(name: 'Deftones').to_a # => [#<Band _id: 5ebdeddfe1b83265a376a760, name: "Deftones", description: nil>]
first
や last
などのメソッドは、個々のドキュメントをすぐに返します。それ以外の場合は、each
や map
などのメソッドを使用して Criteria オブジェクトを反復処理すると、サーバーからドキュメントが検索されます。to_a
は、ドキュメントの配列を返すクエリを強制的に実行するために使用でき、文字通り Criteria オブジェクトを配列に変換します。
クエリ メソッドが Criteria インスタンスで呼び出されると、メソッドは既存の条件に新しい条件が追加された新しい Criteria インスタンスを返します。
scope = Band.where(:founded.gte => "1980-01-01") # => #<Mongoid::Criteria # selector: {"founded"=>{"$gte"=>"1980-01-01"}} # options: {} # class: Band # embedded: false> scope.where(:founded.lte => "2020-01-01") # => #<Mongoid::Criteria # selector: {"founded"=>{"$gte"=>"1980-01-01", "$lte"=>"2020-01-01"}} # options: {} # class: Band # embedded: false> scope # => #<Mongoid::Criteria # selector: {"founded"=>{"$gte"=>"1980-01-01"}} # options: {} # class: Band # embedded: false>
条件構文
Mongoid は、個々の条件を指定する 3 つの方法をサポートしています。
フィールド構文。
MQL構文。
シンボル演算子の構文。
すべての構文は、ドット表記を使用した埋め込みドキュメントのクエリをサポートしています。すべての構文は、クエリ対象のフィールドがモデル クラスで定義されている場合、フィールド型とフィールド エイリアスを尊重します。
このセクションの例では、次のモデル定義を使用します。
class Band include Mongoid::Document field :name, type: String field :founded, type: Integer field :m, as: :member_count, type: Integer embeds_one :manager end class Manager include Mongoid::Document embedded_in :band field :name, type: String end
フィールド構文
最も単純なクエリ構文では、基本的な Ruby ハッシュが使用されます。キーはシンボルまたは文字列にすることができ、MongoDB ドキュメント内のフィールド名に対応します。
Band.where(name: "Depeche Mode") # => #<Mongoid::Criteria # selector: {"name"=>"Depeche Mode"} # options: {} # class: Band # embedded: false> # Equivalent to: Band.where("name" => "Depeche Mode")
MQL 構文
MQL 演算子は、ハッシュ構文を使用して任意のフィールドに指定できます。
Band.where(founded: {'$gt' => 1980}) # => #<Mongoid::Criteria # selector: {"founded"=>{"$gt"=>1980}} # options: {} # class: Band # embedded: false> # Equivalent to: Band.where('founded' => {'$gt' => 1980})
シンボル演算子構文
MQL 演算子は、次のように、それぞれのフィールド名のシンボルのメソッドとして指定できます。
Band.where(:founded.gt => 1980) # => #<Mongoid::Criteria # selector: {"founded"=>{"$gt"=>1980}} # options: {} # class: Band # embedded: false>
フィールド
定義済みフィールドのクエリ
フィールドをクエリするために、 モデル クラス定義にフィールドを追加する必要はありません。ただし、モデル クラスでフィールドが定義されている場合、Mongoid はクエリを構築するときに、定義されたフィールド型と一致するようにクエリ値を強制します。
Band.where(name: 2020, founded: "2020") # => #<Mongoid::Criteria # selector: {"name"=>"2020", "founded"=>2020} # options: {} # class: Band # embedded: false>
Raw Values のクエリ
Mongoid のクエリ型強制動作をバイパスし、データベース内の未加工の型値を直接クエリする場合は、クエリ値をMongoid::RawValue
クラスでラップします。 これは、レガシー データを操作する際に役立ちます。
Band.where(founded: Mongoid::RawValue("2020")) # => #<Mongoid::Criteria # selector: {"founded"=>"2020"} # options: {} # class: Band # embedded: false>
フィールド エイリアス
クエリでは、ストレージ フィールド名とフィールド エイリアスが考慮されます。
Band.where(name: 'Astral Projection') # => #<Mongoid::Criteria # selector: {"n"=>"Astral Projection"} # options: {} # class: Band # embedded: false>
id
フィールドと _id
フィールドはエイリアスなので、どちらもクエリに使用できます。
Band.where(id: '5ebdeddfe1b83265a376a760') # => #<Mongoid::Criteria # selector: {"_id"=>BSON::ObjectId('5ebdeddfe1b83265a376a760')} # options: {} # class: Band # embedded: false>
埋め込みドキュメント
埋め込まれたドキュメントのフィールドの値を一致させるには、ドット表記を使用します。
Band.where('manager.name' => 'Smith') # => #<Mongoid::Criteria # selector: {"manager.name"=>"Smith"} # options: {} # class: Band # embedded: false> Band.where(:'manager.name'.ne => 'Smith') # => #<Mongoid::Criteria # selector: {"manager.name"=>{"$ne"=>"Smith"}} # options: {} # class: Band # embedded: false>
注意
すべての条件が埋め込みドキュメントを参照している場合でも、クエリは常に最上位のモデル インスタンスを返します。
論理演算
Mongoid は、Criteria
オブジェクトに対する and
、or
、nor
、および not
の論理演算をサポートします。これらのメソッドは、1 つ以上の条件のハッシュまたは別の Criteria
オブジェクトを引数として受け取ります。not
には引数なしのバージョンも追加されます。
# and with conditions Band.where(label: 'Trust in Trance').and(name: 'Astral Projection') # or with scope Band.where(label: 'Trust in Trance').or(Band.where(name: 'Astral Projection')) # not with conditions Band.not(label: 'Trust in Trance', name: 'Astral Projection') # argument-less not Band.not.where(label: 'Trust in Trance', name: 'Astral Projection')
以前の Mongoid バージョンとの下位互換性のため、すべての論理演算メソッドはパラメーターの配列も受け入れ、基準を取得するためにフラット化されます。論理演算に配列を渡すことは非推奨であり、Mongoid の将来のバージョンでは削除される可能性があります。
次の呼び出しはすべて同じクエリ条件を生成します。
# Condition hashes passed to separate and invocations Band.and(name: 'SUN Project').and(member_count: 2) # Multiple condition hashes in the same and invocation Band.and({name: 'SUN Project'}, {member_count: 2}) # Multiple condition hashes in an array - deprecated Band.and([{name: 'SUN Project'}, {member_count: 2}]) # Condition hash in where and a scope Band.where(name: 'SUN Project').and(Band.where(member_count: 2)) # Condition hash in and and a scope Band.and({name: 'SUN Project'}, Band.where(member_count: 2)) # Scope as an array element, nested arrays - deprecated Band.and([Band.where(name: 'SUN Project'), [{member_count: 2}]]) # All produce: # => #<Mongoid::Criteria # selector: {"name"=>"SUN Project", "member_count"=>2} # options: {} # class: Band # embedded: false>
演算子の組み合わせ
Mongoid7.1 以降、論理演算子(and
、or
、nor
、not
)は 、ActiveRecord 論理演算子 と同じセマンティクスを持つように変更されました。 。Mongoid 7でのor
の動作のセマンティクスを取得します。 0以前の場合は、以下で説明するany_of
を使用します。
同じフィールドに条件が複数回指定されている場合、すべての条件が基準に追加されます。
Band.where(name: 1).where(name: 2).selector # => {"name"=>"1", "$and"=>[{"name"=>"2"}]} Band.where(name: 1).or(name: 2).selector # => {"$or"=>[{"name"=>"1"}, {"name"=>"2"}]}
any_of
、none_of
、nor
、not
は同様に動作しますが、not
は以下に示すように異なるクエリシェイプを生成します。
and
、or
、nor
論理演算子が使用される場合、それらはその時点までに構築された基準とその引数に基づいて動作します。where
は and
と同じ意味を持ちます:
# or joins the two conditions Band.where(name: 'Sun').or(label: 'Trust').selector # => {"$or"=>[{"name"=>"Sun"}, {"label"=>"Trust"}]} # or applies only to the first condition, the second condition is added # to the top level as $and Band.or(name: 'Sun').where(label: 'Trust').selector # => {"$or"=>[{"name"=>"Sun"}], "label"=>"Trust"} # Same as previous example - where and and are aliases Band.or(name: 'Sun').and(label: 'Trust').selector # => {"$or"=>[{"name"=>"Sun"}], "label"=>"Trust"} # Same operator can be stacked any number of times Band.or(name: 'Sun').or(label: 'Trust').selector # => {"$or"=>[{"name"=>"Sun"}, {"label"=>"Trust"}]} # The label: Foo condition is added to the top level as $and Band.where(name: 'Sun').or(label: 'Trust').where(label: 'Foo').selector # => {"$or"=>[{"name"=>"Sun"}, {"label"=>"Trust"}], "label"=>"Foo"}
and
動作
and
メソッドは、受信基準にそれぞれのフィールドの条件がすでに設定されていない限り、基準の最上位レベルに新しい単純な条件を追加します。設定されている場合、条件は $and
と結合されます。
Band.where(label: 'Trust in Trance').and(name: 'Astral Projection').selector # => {"label"=>"Trust in Trance Records", "name"=>"Astral Projection"} Band.where(name: /Best/).and(name: 'Astral Projection').selector # => {"name"=>/Best/, "$and"=>[{"name"=>"Astral Projection"}]}
Mongoid 7.1 以降では、and
を使用して同じフィールドに複数の条件を指定すると、指定されたすべての条件が結合されますが、以前のバージョンの Mongoid では、使用された and
の形式に応じて、フィールドの条件が同じフィールドで以前に指定された条件を置き換えることがありました。
or
/nor
Behavior _----------------------
or
および nor
は、レシーバーとすべての引数をオペランドとして使用して、それぞれ $or
および $nor
MongoDB 演算子を生成します。例:
Band.where(name: /Best/).or(name: 'Astral Projection') # => {"$or"=>[{"name"=>/Best/}, {"name"=>"Astral Projection"}]} Band.where(name: /Best/).and(name: 'Astral Projection'). or(Band.where(label: /Records/)).and(label: 'Trust').selector # => {"$or"=>[{"name"=>/Best/, "$and"=>[{"name"=>"Astral Projection"}]}, {"label"=>/Records/}], "label"=>"Trust"}
レシーバーの唯一の条件が別の or
/nor
である場合、新しい条件が既存のリストに追加されます。
Band.where(name: /Best/).or(name: 'Astral Projection'). or(Band.where(label: /Records/)).selector # => {"$or"=>[{"name"=>/Best/}, {"name"=>"Astral Projection"}, {"label"=>/Records/}]}
これまでに構築されたすべての条件をそのまま維持しながら、Criteria オブジェクトに論理和を追加するには、any_of
を使用します。
any_of
動作
any_of
引数から構築された論理和を基準内の既存の条件に追加します。例:
Band.where(label: /Trust/).any_of({name: 'Astral Projection'}, {name: /Best/}) # => {"label"=>/Trust/, "$or"=>[{"name"=>"Astral Projection"}, {"name"=>/Best/}]}
可能な場合は、条件が最上位レベルに引き上げられます。
Band.where(label: /Trust/).any_of({name: 'Astral Projection'}) # => {"label"=>/Trust/, "name"=>"Astral Projection"}
none_of
動作
none_of
は、その引数から構築された否定論理和(「nor」)を基準内の既存の条件に追加します。例:
Band.where(label: /Trust/).none_of({name: 'Astral Projection'}, {name: /Best/}) # => {"label"=>/Trust/, "$nor"=>[{"name"=>"Astral Projection"}, {"name"=>/Best/}]}
not
動作
not
メソッドは引数なしで呼び出すことができます。その場合、指定された次の条件は否定されます。not
は、1 つ以上のハッシュ条件または Criteria
オブジェクトを使用して呼び出すこともできます。これらはすべて否定されて条件に追加されます。
# not negates subsequent where Band.not.where(name: 'Best').selector # => {"name"=>{"$ne"=>"Best"}} # The second where is added as $and Band.not.where(name: 'Best').where(label: /Records/).selector # => {"name"=>{"$ne"=>"Best"}, "label"=>/Records/} # not negates its argument Band.not(name: 'Best').selector # => {"name"=>{"$ne"=>"Best"}}
注意
$not
(MongoDBサーバー内)は文字列引数では使用できません。Mongoid は、このような否定を実現するために $ne
演算子を使用します。
# String negation - uses $ne Band.not.where(name: 'Best').selector # => {"name"=>{"$ne"=>"Best"}} # Regexp negation - uses $not Band.not.where(name: /Best/).selector # => {"name"=>{"$not"=>/Best/}}
and
と同様に、not
は単純なフィールド基準の個々の条件を否定します。複雑な条件の場合、およびフィールドにすでに条件が定義されている場合、MongoDB サーバーはグローバルではなくフィールドごとにのみ $not
演算子をサポートするため、Mongoid は {'$and' => [{'$nor' => ...}]}
構造を使用して $not
をエミュレートします。
# Simple condition Band.not(name: /Best/).selector # => {"name"=>{"$not"=>/Best/}} # Complex conditions Band.where(name: /Best/).not(name: 'Astral Projection').selector # => {"name"=>/Best/, "$and"=>[{"$nor"=>[{"name"=>"Astral Projection"}]}]} # Symbol operator syntax Band.not(:name.ne => 'Astral Projection') # => #<Mongoid::Criteria # selector: {"$and"=>[{"$nor"=>[{"name"=>{"$ne"=>"Astral Projection"}}]}]} # options: {} # class: Band # embedded: false>
配列または正規表現とともにnot
を使用する場合は、 MongoDB サーバーのドキュメント に記載されている$not
の警告と制限に注意してください。
増分クエリ構築
デフォルトでは、条件がクエリに追加されると、Mongoid は各条件が完了し、クエリ内に存在する可能性のある他の条件から独立していると見なします。たとえば、in
を 2 回呼び出すと、2 つの個別の $in
条件が追加されます。
Band.in(name: ['a']).in(name: ['b']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["a"]}, "$and"=>[{"name"=>{"$in"=>["b"]}}]} options: {} class: Band embedded: false>
一部の演算子メソッドは、条件を段階的にビルドすることをサポートしています。この場合、サポートされている演算子の 1 つを使用するフィールドの条件が追加されるときに、同じフィールドに同じ演算子を使用する条件がすでに存在する場合は、指定された マージ戦略 に従って演算子式が結合されます。
合併戦略
Mongoid は 3 つのマージ戦略を提供します。
オーバーライド: 新しい演算子インスタンスは、同じ演算子を使用する同じフィールドの既存の条件を置き換えます。
交差: 同じフィールドで同じ演算子を使用する条件が既に存在する場合、既存の条件の値と新しい条件の値が交差され、その結果が演算子値として保存されます。
結合: 同じフィールドで同じ演算子を使用する条件が既に存在する場合、新しい条件の値が既存の条件の値に追加され、結果が演算子値として保存されます。
次のスニペットは、in
を例の演算子として使用して、すべての戦略を示しています。
Band.in(name: ['a']).override.in(name: ['b']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["b"]}} options: {} class: Band embedded: false> Band.in(name: ['a', 'b']).intersect.in(name: ['b', 'c']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["b"]}} options: {} class: Band embedded: false> Band.in(name: ['a']).union.in(name: ['b']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["a", "b"]}} options: {} class: Band embedded: false>
この戦略は、Criteria
インスタンスで override
、intersect
、または union
を呼び出すことによってリクエストされます。リクエストされた戦略は、クエリで呼び出される次の条件メソッドに適用されます。次に呼び出される条件メソッドがマージ戦略をサポートしていない場合、次の例に示すように、戦略はリセットされます。
Band.in(name: ['a']).union.ne(name: 'c').in(name: ['b']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["a"], "$ne"=>"c"}, "$and"=>[{"name"=>{"$in"=>["b"]}}]} options: {} class: Band embedded: false>
ne
はマージ戦略をサポートしていないため、union
戦略は無視されてリセットされ、in
が 2 回目に呼び出されたときにアクティブな戦略がありませんでした。
警告
現在のところ、マージ戦略では前の条件がクエリの最上位に追加されていることを前提としていますが、常にそうであるとは限りません(条件は $and
句の下にネストされている場合があります)。複雑な条件でマージ戦略を使用すると、誤ったクエリが構築される可能性があります。この不具合は将来修正される予定です。
サポートされている演算子メソッド
次の演算子メソッドはマージ戦略をサポートします。
all
in
nin
このメソッドのセットは、Mongoid の将来のリリースで拡張される可能性があります。将来の互換性のために、次のメソッド呼び出しがマージ戦略をサポートする演算子である場合にのみ、戦略メソッドを呼び出します。
マージ戦略は現在、指定されたメソッドを通じて条件が追加された場合にのみ適用されることに注意してください。次の例では、2 つ目の条件が in
ではなく where
経由で追加されているため、マージ戦略は適用されません。
Band.in(foo: ['a']).union.where(foo: {'$in' => 'b'}) => #<Mongoid::Criteria selector: {"foo"=>{"$in"=>["a"]}, "$and"=>[{"foo"=>{"$in"=>"b"}}]} options: {} class: Band embedded: false>
この動作は Mongoid の将来のリリースで変更される可能性があるため、依存しないでください。
対照的に、マージ戦略をサポートする演算子メソッドが呼び出される場合、既存のクエリがどのように構築されたかは問題ではありません。次の例では、最初の条件は where
を通じて追加されましたが、戦略メカニズムは引き続き適用されます。
Band.where(foo: {'$in' => ['a']}).union.in(foo: ['b']) => #<Mongoid::Criteria selector: {"foo"=>{"$in"=>["a", "b"]}} options: {} class: Band embedded: false>
演算子値の拡張
マージ戦略をサポートする演算子メソッドはすべて、値の型として Array
を受け取ります。Mongoid は、次の演算子メソッドで使用される場合、Range
などの Array
互換型を拡張します。
Band.in(year: 1950..1960) => #<Mongoid::Criteria selector: {"year"=>{"$in"=>[1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960]}} options: {} class: Band embedded: false>
さらに、次の例に示すように、Mongoid は歴史的に Array
以外の値を配列にラップしてきました。
Band.in(year: 1950) => #<Mongoid::Criteria selector: {"year"=>{"$in"=>[1950]}} options: {} class: Band embedded: false>
クエリメソッド
elem_match
このマッチャーは、配列値の 1 つがすべての条件に一致する配列フィールドを持つドキュメントを検索します。例:
class Band include Mongoid::Document field :name, type: String field :tours, type: Array end aerosmith = Band.create!(name: 'Aerosmith', tours: [ {city: 'London', year: 1995}, {city: 'New York', year: 1999}, ]) Band.elem_match(tours: {city: 'London'}).to_a # => [aerosmith]
elem_match
は、埋め込み関連付けでも機能します。
class Band include Mongoid::Document field :name, type: String embeds_many :tours end class Tour include Mongoid::Document field :city, type: String field :year, type: Integer embedded_in :band end dm = Band.create!(name: 'Depeche Mode') aerosmith = Band.create!(name: 'Aerosmith') Tour.create!(band: aerosmith, city: 'London', year: 1995) Tour.create!(band: aerosmith, city: 'New York', year: 1999) Band.elem_match(tours: {city: 'London'}).to_a # => [aerosmith]
elem_match
MongoDB には結合がないため、非埋め込み関連付けでは機能しません。条件は、関連付けのターゲットのコレクションではなく、非埋め込み関連付けのソースであるコレクションに追加されます。
elem_match
次の例に示すように、再帰的に埋め込まれた関連付けで使用することもできます。
class Tag include Mongoid::Document field :name, type: String recursively_embeds_many end root = Tag.create!(name: 'root') sub1 = Tag.new(name: 'sub1', child_tags: [Tag.new(name: 'subsub1')]) root.child_tags << sub1 root.child_tags << Tag.new(name: 'sub2') root.save! Tag.elem_match(child_tags: {name: 'sub1'}).to_a # => [root] root.child_tags.elem_match(child_tags: {name: 'subsub1'}).to_a # => [sub1]
プロジェクション
Mongoid は、only
と without
の 2 つのプロジェクション演算子を提供します。
only
only
メソッドは、データベースから指定されたフィールドのみを検索します。この操作は「プロジェクション」と呼ばれることもあります。
class Band include Mongoid::Document field :name, type: String field :label, type: String embeds_many :tours end class Tour include Mongoid::Document field :city, type: String field :year, type: Integer embedded_in :band end band = Band.only(:name).first
ロードされていない属性を参照しようとすると、Mongoid::Errors::AttributeNotLoaded
が発生します。
band.label #=> raises Mongoid::Errors::AttributeNotLoaded
Mongoid は現在、ロードされていない属性への書き込みを許可していますが、このような書込みは保持されません( MONGOID-4701 )のため、 は避けてください。
only
は埋め込み関連付けでも使用できます。
band = Band.only(:name, 'tours.year').last # => #<Band _id: 5c59afb1026d7c034dba46ac, name: "Aerosmith"> band.tours.first # => #<Tour _id: 5c59afdf026d7c034dba46af, city: nil, year: 1995>
注意
サーバー バージョン 4.2 以前では、次のように、同じクエリで関連付けと関連付けのフィールドの両方を投影されました。
band = Band.only(:tours, 'tours.year').last
最新のプロジェクション仕様が以前のものを上書きします。たとえば、上記のクエリは次のクエリと同等です。
band = Band.only('tours.year').last
サーバー バージョン 4.4 以降では、同じクエリで関連付けとそのプロジェクションのフィールドを指定することは禁止されています。
only
参照された関連付け(has_one、has_many、has_and_belongs_to_many)で指定できますが、現在は参照された関連付けでは無視され、参照されたすべての関連付けのフィールドがロードされます (MONGOID-4704)。
ドキュメントに has_one
または has_and_belongs_to_many
の関連付けがある場合、それらの関連付けをロードするには、外部キーを持つフィールドが only
でロードされる属性のリストに含まれている必要があることに注意してください。例:
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 band = Band.create!(name: 'Astral Projection') band.managers << Manager.new Band.where(name: 'Astral Projection').only(:name).first.managers # => [] Band.where(name: 'Astral Projection').only(:name, :manager_ids).first.managers # => [#<Manager _id: 5c5dc2f0026d7c1730969843, band_ids: [BSON::ObjectId('5c5dc2f0026d7c1730969842')]>]
without
only
の反対で、without
は指定されたフィールドを省略します。
Band.without(:name) # => # #<Mongoid::Criteria # selector: {} # options: {:fields=>{"name"=>0}} # class: Band # embedded: false>
Mongoid はさまざまな操作に _id
フィールドを必要とするため、このフィールド(およびその id
エイリアス)を without
で省略することはできません。
Band.without(:name, :id) # => # #<Mongoid::Criteria # selector: {} # options: {:fields=>{"name"=>0}} # class: Band # embedded: false> Band.without(:name, :_id) # => # #<Mongoid::Criteria # selector: {} # options: {:fields=>{"name"=>0}} # class: Band # embedded: false>
順序
Mongoid は、ドキュメントの順序を指定するために、Criteria
オブジェクトとそのエイリアスである order_by
に order
メソッドを提供します。これらのメソッドは、ドキュメントをどのフィールドで並べ替えるか、および各フィールドに対して昇順または降順のどちらを使用するかを示すハッシュを受け取ります。
Band.order(name: 1) # => #<Mongoid::Criteria # selector: {} # options: {:sort=>{"name"=>1}} # class: Band # embedded: false> Band.order_by(name: -1, description: 1) # => #<Mongoid::Criteria # selector: {} # options: {:sort=>{"name"=>-1, "description"=>1}} # class: Band # embedded: false> Band.order_by(name: :desc, description: 'asc') # => #<Mongoid::Criteria # selector: {} # options: {:sort=>{"name"=>-1, "description"=>1}} # class: Band # embedded: false>
方向は、昇順と降順を表す整数 1
と -1
、またはシンボル :asc
と :desc
、あるいは文字列 "asc"
と "desc"
として指定できます。
あるいは、order
は順序を指定する 2 要素の配列の配列を受け入れます。フィールド名と方向は文字列または記号にすることができます。
Band.order([['name', 'desc'], ['description', 'asc']]) Band.order([[:name, :desc], [:description, :asc]])
順序を指定する別の方法は、次のようにシンボルに対して #asc
メソッドと #desc
メソッドを使用することです。
Band.order(:name.desc, :description.asc)
引数は、SQL 構文を使用して文字列として指定できます。
Band.order('name desc, description asc')
最後に、order
/order_by
の代わりに使用できる asc
メソッドと desc
メソッドがあります。
Band.asc('name').desc('description') # => #<Mongoid::Criteria selector: {} options: {:sort=>{"name"=>1, "description"=>-1}} class: Band embedded: false>
order
呼び出しは連鎖させることができ、その場合、最も古い呼び出しが最も重要な基準を定義し、最も新しい呼び出しが最も重要な基準を定義します(Ruby ではハッシュがキーの順序を維持するため)。
Band.order('name desc').order('description asc') # => #<Mongoid::Criteria selector: {} options: {:sort=>{"name"=>-1, "description"=>1}} class: Band embedded: false>
デフォルトのスコープを含め、order
/order_by
を使用するスコープがある場合、予期しない結果が生じることがあります。たとえば、次のスニペットでは、デフォルトのスコープが最初に評価されるため、デフォルトのスコープ内の順序がクエリで指定された順序よりも優先され、バンドは最初に名前で順序付けられます。
class Band include Mongoid::Document field :name, type: String field :year, type: Integer default_scope -> { order(name: :asc) } end Band.order(year: :desc) # => #<Mongoid::Criteria selector: {} options: {:sort=>{"name"=>1, "year"=>-1}} class: Band embedded: false>
ページ分割
Mongoid は、Criteria
でページネーション演算子 limit
、skip
、および batch_size
を提供します。
limit
limit
はクエリによって返されるドキュメントの合計数を設定します。
Band.limit(5) # => # #<Mongoid::Criteria # selector: {} # options: {:limit=>5} # class: Band # embedded: false>
skip
skip
(エイリアス: offset
)は、ドキュメントを返す前にスキップするクエリ結果の数を設定します。 limit
値が指定されている場合は、ドキュメントがスキップされた後にこの値が適用されます。 ページネーションを行う際には、一貫した結果を得るために、 skip
を使用する際にクエリの順序も指定することをお勧めします。
Band.skip(10) # => # #<Mongoid::Criteria # selector: {} # options: {:skip=>10} # class: Band # embedded: false>
batch_size
大規模なクエリを実行する場合、または Criteria#each
などの列挙メソッドを使用してクエリ結果を反復処理する場合、Mongoid は自動的に MongoDB getMore コマンドを使用して結果をバッチで読み込みます。デフォルトの batch_size
は 1000 ですが、明示的に設定することもできます。
Band.batch_size(500) # => # #<Mongoid::Criteria # selector: {} # options: {:batch_size=>500} # class: Band # embedded: false>
検索方法 _id
Mongoid は、_id
値でドキュメントを検索するために、Criteria
オブジェクトに find
メソッドを提供します。
Band.find('5f0e41d92c97a64a26aabd10') # => #<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor">
find
メソッドは、必要に応じて、引数を _id
フィールドに対して照会されているモデルで宣言された型に変換します。デフォルトでは、_id
型は BSON::ObjectId
であるため、上記のクエリは次のクエリと同等になります。
Band.find(BSON::ObjectId.from_string('5f0e41d92c97a64a26aabd10')) # => #<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor">
注意
ドライバーを使用してコレクションを直接クエリする場合、型変換は自動的に実行されません。
Band.collection.find(_id: BSON::ObjectId.from_string('5f0e41d92c97a64a26aabd10')).first # => {"_id"=>BSON::ObjectId('5f0e41d92c97a64a26aabd10'), "name"=>"Juno Reactor"} Band.collection.find(_id: '5f0e41d92c97a64a26aabd10').first # => nil
find
メソッドは複数の引数、または引数の配列を受け入れることができます。どちらの場合も、各引数または配列要素は _id
値として扱われ、指定されたすべての _id
値を持つドキュメントが配列で返されます。
Band.find('5f0e41d92c97a64a26aabd10', '5f0e41b02c97a64a26aabd0e') # => [#<Band _id: 5f0e41b02c97a64a26aabd0e, name: "SUN Project", description: nil, likes: nil>, #<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor", description: nil, likes: nil>] Band.find(['5f0e41d92c97a64a26aabd10', '5f0e41b02c97a64a26aabd0e']) # => [#<Band _id: 5f0e41b02c97a64a26aabd0e, name: "SUN Project", description: nil, likes: nil>, #<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor", description: nil, likes: nil>]
同じ _id
値が複数回指定されている場合、対応するドキュメントは 1 回だけ返されます。
Band.find('5f0e41b02c97a64a26aabd0e', '5f0e41b02c97a64a26aabd0e') # => [#<Band _id: 5f0e41b02c97a64a26aabd0e, name: "SUN Project", description: nil, likes: nil>]
返されるドキュメントは順序付けられておらず、上記の例に示すように、指定された _id
値の順序とは異なる順序で返される場合があります。
_id
値のいずれかがデータベースで見つからない場合、find
の動作は raise_not_found_error
構成オプションの値によって異なります。オプションが true
に設定されている場合に _id
のいずれかが見つからない場合は、find
で Mongoid::Errors::DocumentNotFound
が発生します。オプションを false
に設定し、 find
に検索目的で単一の _id
が与えられ、一致するドキュメントがない場合、find
は nil
を返します。オプションが false
に設定され、find
に検索対象の ID の配列が指定され、一部が見つからなかった場合、戻り値は見つかったドキュメントの配列になります(ドキュメントがまったく見つからなかった場合は空になる可能性があります)。
追加のクエリメソッド
Mongoid には、基準に関する役立つメソッドもいくつかあります。
操作 | 例 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
フィルターに一致するドキュメントの合計数、またはコレクション内のドキュメントの合計数を取得します。カウントのために常にデータベースがヒットすることに注意してください。 Mongoid 7.2 以降、 |
| ||||||||||||||||
コレクションのメタデータを使用して、コレクション内のドキュメントのおおよその数を取得します。 |
| ||||||||||||||||
単一のフィールドの個別の値のリストを取得します。異なる値については、常にデータベースにアクセスすることに注意してください。 このメソッドはドット表記を受け入れるため、埋め込まれた関連付け内のフィールドを参照できます。 このメソッドは、埋め込みドキュメントで定義されているものも含め、:ref:`フィールド エイリアス <field-aliases>` を尊重します。 |
| ||||||||||||||||
条件に一致するすべてのドキュメントを反復処理します。 |
| ||||||||||||||||
一致するドキュメントが存在するかどうかを判断します。1 個以上の場合は true を返します。
|
| ||||||||||||||||
指定された条件に該当する 5 番目のドキュメントを取得します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
指定された条件に該当する 5 番目のドキュメントを取得します。存在しない場合はエラーが発生します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
指定された属性でドキュメントを検索します。見つからない場合は、
|
| ||||||||||||||||
指定された属性でドキュメントを検索し、見つからない場合は新しく作成して保存したものを返します。このメソッドの引数で指定された属性は、「create_with」で設定された属性を上書きすることに注意してください。 |
| ||||||||||||||||
指定された属性でドキュメントを検索し、見つからない場合は新しいドキュメントを返します。 |
| ||||||||||||||||
指定された条件に従って単一のドキュメントを検索します。制限引数を渡してドキュメントのリストを取得します。このメソッドは、_id に基づいて自動的にソートを追加します。これによりパフォーマンスの問題が発生する可能性があるため、ソートが望ましくない場合は、代わりに Criteria#take を使用できます。 |
| ||||||||||||||||
指定された条件に従って単一のドキュメントを検索します。見つからない場合はエラーが発生します。このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。これによりパフォーマンスの問題が発生する可能性があるため、並べ替えが望ましくない場合は、代わりに Criteria#take! を使用できます。 |
| ||||||||||||||||
指定された属性で最初のドキュメントを検索し、見つからない場合は新しく保存されたドキュメントを作成して返します。 |
| ||||||||||||||||
指定された属性で最初のドキュメントを検索し、見つからない場合は、新しく保存されたドキュメントを作成して返します。 |
| ||||||||||||||||
指定された属性で最初のドキュメントを検索し、見つからない場合は新しいドキュメントを返します。 |
| ||||||||||||||||
指定された JavaScript 式のドキュメントを検索します。オプションで、指定された変数を評価スコープに追加します。スコープ引数は MongoDB 4.2 以前でサポートされています。
好み $expr over |
| ||||||||||||||||
指定された条件に該当する 4 番目のドキュメントを取得します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
指定された条件に一致する 4 番目のドキュメントを取得します。存在しない場合はエラーが発生します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
countと同じですが、データベースへの後続の呼び出しをキャッシュします。 |
| ||||||||||||||||
指定されたフィールドの値を 1 つのドキュメントから取得します。設定されていないフィールドおよび存在しないフィールドの場合は nil を返します。 このメソッドはドキュメントにソートを適用しないため、必ずしも最初のドキュメントの値が返されるわけではありません。 このメソッドはドット表記を受け入れるため、埋め込まれた関連付け内のフィールドを参照できます。 このメソッドは、埋め込みドキュメントで定義されているものも含め、:ref:`フィールド エイリアス <field-aliases>` を尊重します。 |
| ||||||||||||||||
指定されたフィールドのすべての値を取得します。設定されていないフィールドおよび存在しないフィールドの場合は nil を返します。 このメソッドはドット表記を受け入れるため、埋め込まれた関連付け内のフィールドを参照できます。 このメソッドは、埋め込みドキュメントで定義されているものも含め、:ref:`フィールド エイリアス <field-aliases>` を尊重します。 |
| ||||||||||||||||
基準の読み込み設定 (read preference) を設定します。 |
| ||||||||||||||||
指定された条件に該当する 2 番目のドキュメントを取得します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
指定された条件に該当する 2 番目のドキュメントを取得します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
指定された条件に該当する最後から 2 番目のドキュメントを取得します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
指定された条件に一致する最後から 2 番目のドキュメントを取得します。存在しない場合はエラーが発生します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
データベースから n 個のドキュメントのリストを取得します。パラメーターが指定されていない場合は 1 つのドキュメントのみを取得します。 このメソッドはドキュメントにソートを適用しないため、#first および #last とは異なるドキュメントを返す場合があります。 |
| ||||||||||||||||
データベースからドキュメントを取得するか、ドキュメントが存在しない場合はエラーを発生させます。 このメソッドはドキュメントにソートを適用しないため、#first および #last とは異なるドキュメントを返す場合があります。 |
| ||||||||||||||||
指定されたフィールドの値とカウントのマッピングを取得します。 このメソッドはドット表記を受け入れるため、埋め込まれた関連付け内のフィールドを参照できます。 このメソッドは、埋め込みドキュメントで定義されているものも含め、:ref:`フィールド エイリアス <field-aliases>` を尊重します。 |
| ||||||||||||||||
指定された条件の 3 番目のドキュメントを取得します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
指定された条件に一致する 3 番目のドキュメントを取得します。存在しない場合はエラーが発生します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
指定された条件に該当する最後から 3 番目のドキュメントを取得します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
| ||||||||||||||||
指定された条件に該当する最後から 3 番目のドキュメントを取得します。存在しない場合はエラーが発生します。 このメソッドは、ソートが指定されていない場合、_id に自動的にソートを追加します。 |
|
積載量
Mongoid は、関連付けアクセスを持つドキュメントを反復処理するときに n+1 問題を防ぐために、関連付けからドキュメントを早期ロードする機能を提供します。多態的な belongs_to
関連付けを除くすべての関連付けで、Eager 読み込みがサポートされています。
class Band include Mongoid::Document has_many :albums end class Album include Mongoid::Document belongs_to :band end Band.includes(:albums).each do |band| p band.albums.first.name # Does not hit the database again. end
正規表現
MongoDB と Mongoid では、正規表現によるドキュメントのクエリが可能です。
次のモデル定義があるとします。
class Band include Mongoid::Document field :name, type: String field :description, type: String end Band.create!(name: 'Sun Project', description: "Sun\nProject")
... シンプルな Ruby 正規表現を使用して自然な方法でクエリを実行できます。
Band.where(name: /project/i).first # => #<Band _id: 5dc9f7d5ce4ef34893354323, name: "Sun Project", description: "Sun\nProject">
BSON::Regexp::Raw
オブジェクトを明示的に構築することで、PCRE 構文を使用してクエリを実行することもできます。
Band.where(description: /\AProject/).first # => #<Band _id: 5dc9f7d5ce4ef34893354323, name: "Sun Project", description: "Sun\nProject"> Band.where(description: BSON::Regexp::Raw.new('^Project')).first # => nil Band.where(description: BSON::Regexp::Raw.new('^Project', 'm')).first # => #<Band _id: 5dc9f7d5ce4ef34893354323, name: "Sun Project", description: "Sun\nProject">
フィールドの条件
条件がモデルで定義されたフィールドを使用する場合、条件で指定されている値は、フィールドのルール(存在する場合)に従って変換されます。たとえば、Time
フィールド、Date
フィールド、暗黙的な Object
フィールドを含み、deregistered_at
というフィールドを意図的に定義していない次のモデル定義を検討してください。
class Voter include Mongoid::Document field :born_on, type: Date field :registered_at, type: Time field :voted_at end
それぞれ Date
と Time
の値を使用して born_on
フィールドと registered_at
フィールドをクエリするのは簡単です。
Voter.where(born_on: Date.today).selector # => {"born_on"=>2020-12-18 00:00:00 UTC} Voter.where(registered_at: Time.now).selector # => {"registered_at"=>2020-12-19 04:33:36.939788067 UTC}
ただし、考えられるすべてのシナリオで Date
インスタンスを提供する場合の動作の違いに注意してください。
Voter.where(born_on: Date.today).selector # => {"born_on"=>2020-12-18 00:00:00 UTC} Voter.where(registered_at: Date.today).selector # => {"registered_at"=>2020-12-18 00:00:00 -0500} Voter.where(voted_at: Date.today).selector # => {"voted_at"=>Fri, 18 Dec 2020} Voter.where(deregistered_at: Date.today).selector # => {"deregistered_at"=>2020-12-18 00:00:00 UTC}
Time
型の registered_at
フィールドを使用すると、日付はローカル時間(構成されたタイムゾーンに従って)として解釈されました。Date
型の born_on
フィールドを使用すると、日付は UTC として解釈されました。型なしで定義された voted_at
フィールド(つまり暗黙的に Object
として)を使用すると、構築されたクエリで日付が変更されずに使用されました。存在しないフィールド deregistered_at
を使用すると、日付は UTC であると解釈され、時刻に変換され、Date
フィールドをクエリする動作と一致します。
スコープ設定
スコープは、よりビジネス ドメイン スタイルの構文を使用して共通の基準を再利用する便利な方法を提供します。
名前付きスコープ
名前付きスコープは、指定された名前によって参照される、クラスのロード時に定義される基準です。通常の基準と同様に、これらは遅延され、連鎖可能です。
class Band include Mongoid::Document field :country, type: String field :genres, type: Array scope :english, ->{ where(country: "England") } scope :rock, ->{ where(:genres.in => [ "rock" ]) } end Band.english.rock # Get the English rock bands.
名前付きスコープは、パラメーターを受け取ったり機能を拡張したりするために、プロシージャとブロックを取ることができます。
class Band include Mongoid::Document field :name, type: String field :country, type: String field :active, type: Boolean, default: true scope :named, ->(name){ where(name: name) } scope :active, ->{ where(active: true) do def deutsch tap do |scope| scope.selector.store("origin" => "Deutschland") end end end } end Band.named("Depeche Mode") # Find Depeche Mode. Band.active.deutsch # Find active German bands.
デフォルトでは、Mongoid では、次の例に示すように、既存のクラス メソッドをシャドウするスコープを定義できます。
class Product include Mongoid::Document def self.fresh true end scope :fresh, ->{ where(fresh: true) } end
スコープが既存のクラス メソッドを上書きするときに Mongoid がエラーを発生させるようにするには、scope_overwrite_exception
構成オプション を true
に設定します。
デフォルトのスコープ
デフォルトのスコープは、ほとんどのクエリに同じ基準を適用し、これらの基準をデフォルトとして指定する場合に役立ちます。デフォルトのスコープは、基準オブジェクトを返すプロシージャです。
class Band include Mongoid::Document field :name, type: String field :active, type: Boolean default_scope ->{ where(active: true) } end Band.each do |band| # All bands here are active. end
デフォルト スコープを指定すると、値が単純なリテラルである場合、新しいモデルのフィールドもデフォルト スコープで指定された値に初期化されます。
class Band include Mongoid::Document field :name, type: String field :active, type: Boolean field :num_tours, type: Integer default_scope ->{ where(active: true, num_tours: {'$gt' => 1}) } end # active is set, num_tours is not set Band.new # => #<Band _id: 5c3f7452ce4ef378295ca5f5, name: nil, active: true, num_tours: nil>
フィールド定義とデフォルト スコープの両方にデフォルト値が指定されている場合は、デフォルト スコープの値が優先されることに注意してください。
class Band include Mongoid::Document field :name, type: String field :active, type: Boolean, default: true default_scope ->{ where(active: false) } end Band.new # => #<Band _id: 5c3f74ddce4ef3791abbb088, name: nil, active: false>
前述のように、デフォルト スコープは新しいモデルのフィールドを初期化するため、ドット キーと単純なリテラル値を使用してデフォルト スコープを定義することは可能ですが、推奨されません。
class Band include Mongoid::Document field :name, type: String field :tags, type: Hash default_scope ->{ where('tags.foo' => 'bar') } end Band.create! # => Created document: {"_id"=>BSON::ObjectId('632de48f3282a404bee1877b'), "tags.foo"=>"bar"} Band.create!(tags: { 'foo' => 'bar' }) # => Created document: {"_id"=>BSON::ObjectId('632de4ad3282a404bee1877c'), "tags.foo"=>"bar", "tags"=>{"foo"=>"bar"}} Band.all.to_a # => [ #<Band _id: 632de4ad3282a404bee1877c, tags: {"foo"=>"bar"}> ]
Mongoid 8 では、Mongoid でドット付きキーを使用できるようになり、ドキュメントを作成するときに、スコープが属性にドット付きキーとして追加されます。
Band.new.attribute # => {"_id"=>BSON::ObjectId('632de97d3282a404bee1877d'), "tags.foo"=>"bar"}
一方、クエリを実行する場合、Mongoid は埋め込まれたドキュメントを探します。
Band.create! # => Created document: {"_id"=>BSON::ObjectId('632de48f3282a404bee1877b'), "tags.foo"=>"bar"} Band.where # => #<Mongoid::Criteria selector: {"tags.foo"=>"bar"} options: {} class: Band embedded: false> # This looks for something like: { tags: { "foo" => "bar" } } Band.count # => 0
回避策としては、デフォルトのスコープを複雑なクエリとして定義します。
class Band include Mongoid::Document field :name, type: String field :tags, type: Hash default_scope ->{ where('tags.foo' => {'$eq' => 'bar'}) } end Band.create!(tags: { hello: 'world' }) Band.create!(tags: { foo: 'bar' }) # does not add a "tags.foo" dotted attribute Band.count # => 1
インラインまたはブロックを取ることができる unscoped
を使用して、Mongoid にデフォルトのスコープを適用しないように指示できます。
Band.unscoped.where(name: "Depeche Mode") Band.unscoped do Band.where(name: "Depeche Mode") end
また、Mongoid に後でデフォルトのスコープを明示的に再度適用するように指示して、常に存在するようにすることもできます。
Band.unscoped.where(name: "Depeche Mode").scoped
関連付けの一部であるモデルでデフォルトのスコープを使用している場合は、スコープを再適用するために関連付けを再ロードする必要があります。関連付け内のドキュメントの値を変更して、スコープ指定された関連付け内での可視性に影響する場合は、この点に注意することが重要です。
class Label include Mongoid::Document embeds_many :bands end class Band include Mongoid::Document field :active, default: true embedded_in :label default_scope ->{ where(active: true) } end label.bands.push(band) label.bands # [ band ] band.update_attribute(:active, false) label.bands # [ band ] Must reload. label.reload.bands # []
注意
デフォルトのスコープが適用されると、他のクエリ条件と区別されなくなります。これは、特に or
および nor
演算子を使用する場合に、予期しない動作を引き起こす可能性があります。
class Band include Mongoid::Document field :name field :active field :touring default_scope ->{ where(active: true) } end Band.where(name: 'Infected Mushroom') # => # #<Mongoid::Criteria # selector: {"active"=>true, "name"=>"Infected Mushroom"} # options: {} # class: Band # embedded: false> Band.where(name: 'Infected Mushroom').or(touring: true) # => # #<Mongoid::Criteria # selector: {"$or"=>[{"active"=>true, "name"=>"Infected Mushroom"}, {"touring"=>true}]} # options: {} # class: Band # embedded: false> Band.or(touring: true) # => # #<Mongoid::Criteria # selector: {"$or"=>[{"active"=>true}, {"touring"=>true}]} # options: {} # class: Band # embedded: false>
最後の例では、2 つの条件(active: true
と touring: true
)が $and
と結合されることが予想されるかもしれませんが、Band
クラスにはすでにスコープが適用されているため、or
の論理和分岐の 1 つになります。
ランタイムのデフォルトスコープの上書き
実行時にブロック内のデフォルトのスコープを変更するには、with_scope
メソッドを使用します。
class Band include Mongoid::Document field :country, type: String field :genres, type: Array scope :english, ->{ where(country: "England") } end criteria = Band.with_scope(Band.english) do Band.all end criteria # => # #<Mongoid::Criteria # selector: {"country"=>"England"} # options: {} # class: Band # embedded: false>
注意
with_scope 呼び出しがネストされている場合、ネストされた with_scope ブロックが完了すると、Mongoid 7 は親スコープではなく現在のスコープを nil に設定します。Mongoid 8 は現在のスコープを正しい親スコープに設定します。Mongoid 7.4 以降で Mongoid 8 の動作を実現するには、Mongoid.broken_scoping
グローバル オプションを false に設定します。
クラスメソッド
基準オブジェクトを返すモデル上のクラス メソッドもスコープのように扱われ、連鎖させることもできます。
class Band include Mongoid::Document field :name, type: String field :active, type: Boolean, default: true def self.active where(active: true) end end Band.active
クエリ + 永続性
Mongoid は、複数のドキュメントの挿入、更新、削除を表現力豊かに実行したい場合に、基準に基づいた永続化操作を軽量にサポートします。
警告
次の操作では、order
、limit
、offset
、batch_size
などの基準の順序付けとページ区切りの条件は無視されます。
操作 | 例 | ||
---|---|---|---|
新しく保存されたドキュメントを作成します。 |
| ||
新しく永続化されたドキュメントを作成し、検証が失敗した場合に例外を発生させます。 |
| ||
新しい(未保存の)ドキュメントを作成します。 |
| ||
最初に一致するドキュメントの属性を更新します。 |
| ||
一致するすべてのドキュメントの属性を更新します。 |
| ||
一致するすべてのドキュメントに対して $addToSet を実行します。 |
| ||
一致するすべてのドキュメントに対して $bit を実行します。 |
| ||
一致するすべてのドキュメントに対して $inc を実行します。 |
| ||
一致するすべてのドキュメントに対して $pop を実行します。 |
| ||
一致するすべてのドキュメントに対して $pull を実行します。 |
| ||
一致するすべてのドキュメントに対して $pullAll を実行します。 |
| ||
一致するすべてのドキュメントに対して $push を実行します。 |
| ||
一致するすべてのドキュメントに対して $each を使用して $push を実行します。 |
| ||
一致するすべてのドキュメントに対して $rename を実行します。 |
| ||
一致するすべてのドキュメントに対して $set を実行します。 |
| ||
一致するすべてのドキュメントに対して $unset を実行します。 |
| ||
データベース内の一致するドキュメントをすべて削除します。 |
| ||
すべてのコールバックを実行しながら、データベース内の一致するすべてのドキュメントを削除します。これにより、すべてのドキュメントがメモリに読み込まれるため、コストのかかる操作になる可能性があります。 |
|
クエリ キャッシュ
Ruby MongoDB ドライバー バージョン2.14以降では、クエリ キャッシュ機能が提供されます。 有効にすると、クエリ キャッシュは以前に実行された検索および集計クエリの結果を保存し、クエリを再度実行するのではなく、将来的にそれらを再利用するため、アプリケーションのパフォーマンスが向上し、データベースの負荷が軽減されます。
ドライバーのクエリ キャッシュ動作の詳細については、ドライバー クエリ キャッシュのドキュメントを参照してください。
このセクションの残りの部分では、ドライバー 2.14 0 以降の使用を前提としています。
クエリキャッシュの有効化
クエリ キャッシュは、ドライバーの名前空間または Mongoid の名前空間を使用して有効にできます。
クエリキャッシュの自動有効化
MongoDB Ruby ドライバーは、Rack ウェブリクエストと ActiveJob ジョブ実行のクエリ キャッシュを自動的に有効にするミドルウェアを提供します。手順については、構成ページの「Query Cache Rack ミドルウェア」セクションを参照してください。
クエリ キャッシュ ミドルウェアは、ウェブリクエストやジョブの外部で実行されるコードには適用されないことに注意してください。
クエリキャッシュの手動有効化
コード セグメントに対してクエリ キャッシュを手動で有効にするには、次を使用します。
Mongo::QueryCache.cache do # ... end
クエリ キャッシュは明示的に有効化および無効化することもできますが、上記のブロック形式を使用することをお勧めします。
begin Mongo::QueryCache.enabled = true # ... ensure Mongo::QueryCache.enabled = false end
結果をキャッシュする #first
モデル クラスで first
メソッドを呼び出すと、基になるクエリの _id
フィールドによる昇順の並べ替えが適用されます。これにより、クエリ キャッシュで予期しない動作が発生する可能性があります。
たとえば、モデル クラスで all
を呼び出してから first
を呼び出すと、2 番目のクエリでは最初のクエリのキャッシュされた結果が使用されることが予想されます。ただし、2 番目のクエリに適用されるソートにより、両方の方法でデータベースがクエリされ、その結果が個別にキャッシュされます。
Band.all.to_a #=> Queries the database and caches the results Band.first #=> Queries the database again because of the sort
キャッシュされた結果を使用するには、モデル クラスで all.to_a.first
を呼び出します。
非同期クエリ
Mongoid を使用すると、バックグラウンドでデータベース クエリを非同期に実行できます。これは、さまざまなコレクションからドキュメントを取得する必要がある場合に役立ちます。
非同期クエリをスケジュールするには、Criteria
で load_async
メソッドを呼び出します。
class PagesController < ApplicationController def index @active_bands = Band.where(active: true).load_async @best_events = Event.best.load_async @public_articles = Article.where(public: true).load_async end end
上記の例では、3 つのクエリが非同期実行用にスケジュールされます。クエリの結果には、後で通常どおりアクセスできます。
<ul> <%- @active_bands.each do -%> <li><%= band.name %></li> <%- end -%> </ul>
クエリが非同期実行用にスケジュールされている場合でも、呼び出し元のスレッドで同期的に実行される可能性があります。クエリ結果にアクセスするタイミングに応じて、次の 3 つのシナリオが考えられます。
スケジュールされた非同期タスクがすでに実行されている場合は、結果が返されます。
タスクが開始されたがまだ完了していない場合、呼び出し元のスレッドはタスクが完了するまでブロックされます。
タスクがまだ開始されていない場合は、実行キューから削除され、クエリは呼び出し元のスレッドで同期的に実行されます。
注意
load_async
メソッドは Criteria
オブジェクトを返しますが、クエリ結果にアクセスする場合を除き、このオブジェクトに対して操作を実行しないでください。クエリは load_async
を呼び出した後すぐに実行されるようにスケジュールされているため、Criteria
オブジェクトへのその後の変更は適用されない可能性があります。
非同期クエリ実行の構成
非同期クエリはデフォルトで無効になっています。非同期クエリが無効になっている場合、load_async
は必要に応じてブロックしながら、現在のスレッドでクエリを直ちに実行します。したがって、この場合、条件に対して load_async
を呼び出すことは、クエリの実行を強制するために to_a
を呼び出すこととほぼ同等です。
非同期クエリ実行を有効にするには、次の構成オプションを設定する必要があります。
development: ... options: # Execute asynchronous queries using a global thread pool. async_query_executor: :global_thread_pool # Number of threads in the pool. The default is 4. # global_executor_concurrency: 4