쿼리
이 페이지의 내용
- 조건 구문
- 필드 구문
- MQL 구문
- 기호 연산자 구문
- 필드
- 정의된 필드에 대한 쿼리
- 원시 값 쿼리
- 필드 별칭
- 내장된 문서
- 로직 연산
- 연산자 조합
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" ])
이 쿼리 메서드는 Mongoid::Criteria
객체를 반환합니다. 이 객체는 MQL(MongoDB query language, MongoDB 쿼리 언어)에 맞게 체인화되고 유연하게 평가되는 래퍼(wrapper)입니다. 이 쿼리는 그 결과 세트가 반복될 때 실행됩니다. 예시:
# 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는 개별 조건을 지정하는 다음 세 가지 방법을 지원합니다.
필드 구문
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>
원시 값 쿼리
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
로직 연산을 지원합니다. 이 메서드들은 한 개 이상의 조건 해시 또는 다른 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>
연산자 조합
Mongoid 부터 7.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
인수 없이 메서드를 호출할 수 있습니다. 이 경우 지정된 다음 조건은 무효화됩니다. 한 개 이상의 해시 조건 또는 Criteria
객체를 사용하여 not
을(를) 호출할 수도 있습니다. 이 경우 조건은 모두 무효화되어 기준에 추가됩니다.
# 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
을(를) 두 번 호출하면 개별 $in
조건이 두 개 추가됩니다.
Band.in(name: ['a']).in(name: ['b']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["a"]}, "$and"=>[{"name"=>{"$in"=>["b"]}}]} options: {} class: Band embedded: false>
일부 연산자 메서드는 조건을 점진적으로 구성할 수 있도록 지원합니다. 이 경우 지원되는 연산자 중 한 개를 사용하는 필드에 조건을 추가하려고 할 때, 동일한 연산자를 사용하는 동일한 필드에 이미 조건이 있는 경우에는 지정된 병합 전략에 따라 연산자 표현식이 합쳐집니다.
전략 병합하기
Mongoid는 다음 세 가지 병합 전략을 제공합니다.
Override(재정의): 새 연산자 인스턴스가 동일한 연산자를 사용하여 동일한 필드의 기존 조건을 모두 대체합니다.
Intersect(교차): 동일한 필드에 동일한 연산자를 사용하는 조건이 이미 있는 경우, 기존 조건의 값이 새 조건의 값과 교차되고 그 결과가 연산자 값으로 저장됩니다.
Union(합집합): 동일한 필드에 동일한 연산자를 사용하는 조건이 이미 있는 경우, 새 조건의 값이 기존 조건의 값에 추가되고 그 결과가 연산자 값으로 저장됩니다.
다음 스니펫은 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
을(를) 호출되었을 때는 어떤 전략도 활성화되지 않았습니다.
경고
병합 전략은 현재 이전 조건이 쿼리의 최상위 수준에 추가되었다고 가정하지만, 항상 그런 것은 아닙니다(조건이 $and
절 아래에 중첩될 수도 있음). 복잡한 기준이 있는 병합 전략을 사용하면 잘못된 쿼리가 구성될 수 있습니다. 이 오작동은 향후 수정될 예정입니다.
지원되는 연산자 메서드
병합 전략을 지원하는 연산자 메서드는 다음과 같습니다.
all
in
nin
이후의 Mongoid 릴리스에서 메서드 세트를 확장할 수 있습니다. 앞으로 호환성을 확보하려면 다음 메서드 호출이 병합 전략을 지원하는 연산자인 경우에만 전략 메서드를 호출하세요.
현재 병합 전략은 지정된 메서드를 통해 조건이 추가된 경우에만 적용됩니다. 다음 예시에서는 두 번째 조건이 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는 Array
호환 유형(예: Range
)을 다음 연산자 메서드와 함께 사용할 때 확장합니다.
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
이 매칭 프로그램은 배열 값 중 한 개가 모든 조건과 일치하는 배열 필드가 포함된 문서를 검색합니다. 예시:
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
을(를) 제공합니다.
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
필드가 필요합니다. 따라서 without
을(를) 통해 이 필드(와 그 id
별칭)를 생략할 수는 없습니다.
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
메서드와 해당 메서드의 별칭인 order_by
을(를) 제공하여 문서의 순서를 지정합니다. 이 메서드는 문서의 정렬 기준으로 사용할 필드와 각 필드에 오름차순 또는 내림차순을 사용할지 여부를 나타내는 해시를 사용합니다.
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는 Criteria
객체에 대해 find
메서드를 제공하여 _id
값을 기준으로 문서를 검색합니다.
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
값이 두 번 이상 제공될 경우 해당 문서는 한 번만 반환됩니다.
Band.find('5f0e41b02c97a64a26aabd0e', '5f0e41b02c97a64a26aabd0e') # => [#<Band _id: 5f0e41b02c97a64a26aabd0e, name: "SUN Project", description: nil, likes: nil>]
반환될 문서는 그 순서가 지정되지 않으며, 위 예시에 나온 대로 제공된 _id
값의 순서와 다른 순서로 반환될 수 있습니다.
데이터베이스에서 어떤 _id
값도 찾을 수 없는 경우 find
의 동작은 raise_not_found_error
구성 옵션의 값에 따라 달라집니다. 옵션이 true
로 설정된 경우 find
는 _id
를 찾을 수 없으면 Mongoid::Errors::DocumentNotFound
를 발생시킵니다. 옵션이 false
로 설정되어 있고 find
에 찾을 _id
하나가 주어졌으며 일치하는 문서가 없는 경우 find
는 nil
을 반환합니다. 옵션이 false
로 설정되어 있고 find
에 찾을 ID 배열이 주어졌으며 일부가 발견되지 않은 경우 반환 값은 찾은 문서의 배열입니다(문서가 전혀 발견되지 않았다면 비어 있을 수 있음).
기타 쿼리 메서드
Mongoid의 기준에 유용한 메서드도 몇 가지 있습니다.
작업 | 예시 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
필터와 일치하는 문서의 총 개수 또는 컬렉션 내 문서의 총 개수를 구하세요. 이렇게 하면 계수에 대해 항상 데이터베이스에서 충돌이 발생합니다. Mongoid 7.2부터 |
| ||||||||||||||||
컬렉션 메타데이터를 사용하여 컬렉션의 대략적인 문서 수를 구하세요. 이 |
| ||||||||||||||||
단일 필드에 대한 고유 값 목록을 가져오세요. 이렇게 하면 고유 값에 대해 항상 데이터베이스에서 충돌이 발생합니다. 이 메서드는 점 표기법을 허용하므로 포함 연결에서 필드 참조를 허용합니다. 이 메서드는 내장된 문서에서 정의된 항목이 포함된 :ref:`field aliases <field-aliases>`를 준수합니다. |
| ||||||||||||||||
이 기준에 일치하는 모든 문서를 반복하세요. |
| ||||||||||||||||
일치하는 문서가 있는지 확인하세요. 개수가 1개 이상이면 true를 반환합니다.
|
| ||||||||||||||||
지정된 기준에 맞는 다섯 번째 문서를 가져오세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
지정된 기준에 맞는 다섯 번째 문서를 가져오세요. 문서가 아무것도 없다면 오류를 제기하세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
제공된 속성을 기준으로 문서를 찾으세요. 찾을 수 없다면 오류를 제기하거나, 구성 옵션의 값에 따라 nil을
|
| ||||||||||||||||
제공된 속성을 기준으로 문서를 찾으세요. 찾을 수 없다면 새 영구 문서를 생성해서 반환하세요. 이 메서드의 인수로 제공된 속성이 ``create_with``의 모든 집합을 재정의합니다. |
| ||||||||||||||||
제공된 속성을 기준으로 문서를 찾으세요. 찾을 수 없다면 새 문서를 반환하세요. |
| ||||||||||||||||
제공된 기준에 따라 단일 문서를 찾으세요. limit 인수를 전달하여 문서 목록을 가져오세요. 이 메서드는 _id를 기준으로 한 정렬을 자동으로 추가합니다. 이는 성능 문제를 유발할 수 있습니다. 따라서 정렬이 바람직하지 않은 경우에는 Criteria#take를 대신 사용해도 됩니다. |
| ||||||||||||||||
제공된 기준에 따라 단일 문서를 찾으세요. 아무것도 찾을 수 없다면 오류를 제기하세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. 이는 성능 문제를 유발할 수 있습니다. 따라서 정렬이 바람직하지 않은 경우에는 Criteria#take!를 대신 사용해도 됩니다. |
| ||||||||||||||||
제공된 속성을 기준으로 첫 번째 문서를 찾으세요. 찾을 수 없다면 새 영구 문서를 생성해서 반환하세요. |
| ||||||||||||||||
제공된 속성을 기준으로 첫 번째 문서를 찾으세요. 찾을 수 없다면 다음 항목을 사용하여 새 영구 문서를 생성해서 반환하세요. |
| ||||||||||||||||
제공된 속성을 기준으로 첫 번째 문서를 찾으세요. 찾을 수 없다면 새 문서를 반환하세요. |
| ||||||||||||||||
선택에 따라 지정된 변수를 평가 범위에 추가하여 제공된 JavaScript 표현식에 해당하는 문서를 찾으세요. 범위 인수는 MongoDB 4.2 이하에서 지원됩니다.
Prefer $expr 끝 |
| ||||||||||||||||
지정된 기준에 맞는 네 번째 문서를 가져오세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
지정된 기준에 맞는 네 번째 문서를 가져오세요. 문서가 아무것도 없다면 오류를 제기하세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
개수가 동일하더라도 데이터베이스에 대한 후속 호출을 캐시합니다. |
| ||||||||||||||||
한 문서에서 제공된 필드에 대한 값을 구하세요. 미설정 필드와 무존재 필드에 대해서는 nil을 반환합니다. 이 메서드는 문서에 정렬을 적용하지 않으므로, 첫 번째 문서의 값을 반드시 반환하지는 않습니다. 이 메서드는 점 표기법을 허용하므로 포함 연결에서 필드 참조를 허용합니다. 이 메서드는 내장된 문서에서 정의된 항목이 포함된 :ref:`field aliases <field-aliases>`를 준수합니다. |
| ||||||||||||||||
제공된 필드의 값을 모두 구하세요. 미설정 필드와 무존재 필드에 대해서는 nil을 반환합니다. 이 메서드는 점 표기법을 허용하므로 포함 연결에서 필드 참조를 허용합니다. 이 메서드는 내장된 문서에서 정의된 항목이 포함된 :ref:`field aliases <field-aliases>`를 준수합니다. |
| ||||||||||||||||
기준을 위한 읽기 설정을 설정합니다. |
| ||||||||||||||||
지정된 기준에 맞는 두 번째 문서를 가져오세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
지정된 기준에 맞는 두 번째 문서를 가져오세요. 문서가 아무것도 없다면 오류를 제기하세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
지정된 기준에 맞는 끝에서 두 번째 문서를 가져오세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
지정된 기준에 맞는 끝에서 두 번째 문서를 가져오세요. 문서가 아무것도 없다면 오류를 제기하세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
데이터베이스에서 n개 문서의 목록을 가져오세요. 매개변수가 제공되지 않았다면 문서를 1개만 가져오세요. 이 메서드는 문서에 정렬을 적용하지 않으므로, #first 및 #last 이외의 다른 문서를 반환할 수 있습니다. |
| ||||||||||||||||
데이터베이스에서 문서를 한 개 가져오세요. 문서가 아무것도 없다면 오류를 제기하세요. 이 메서드는 문서에 정렬을 적용하지 않으므로, #first 및 #last 이외의 다른 문서를 반환할 수 있습니다. |
| ||||||||||||||||
제공된 필드에 대한 값과 계수의 매핑을 가져오세요. 이 메서드는 점 표기법을 허용하므로 포함 연결에서 필드 참조를 허용합니다. 이 메서드는 내장된 문서에서 정의된 항목이 포함된 :ref:`field aliases <field-aliases>`를 준수합니다. |
| ||||||||||||||||
지정된 기준에 맞는 세 번째 문서를 가져오세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
지정된 기준에 맞는 세 번째 문서를 가져오세요. 문서가 아무것도 없다면 오류를 제기하세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
지정된 기준에 맞는 끝에서 세 번째 문서를 가져오세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
| ||||||||||||||||
지정된 기준에 맞는 끝에서 번째 문서를 가져오세요. 문서가 아무것도 없다면 오류를 제기하세요. 이 메서드는 정렬을 실행하지 않을 경우 _id를 기준으로 한 정렬을 자동으로 추가합니다. |
|
선행 로딩
Mongoid는 연결 액세스 권한이 있는 문서를 반복할 때 n+1 문제가 발생하지 않도록 연결에서 문서를 선행 로드하는 기능을 제공합니다. 선행 로드는 다형성 belongs_to
연결을 제외한 모든 연결에 대해 지원됩니다.
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에 맞게 해석되었습니다. 유형 없이 정의된(이에 따라 암시적으로 Object
(으)로 정의됨) voted_at
필드를 사용하는 경우, 이 날짜는 구성된 쿼리에서 수정되지 않은 상태로 사용되었습니다. 무존재 필드인 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>
마지막 예시에서는 두 조건(active: true
및 touring: true
)이 $and
와(과) 합쳐질 것으로 예상할 수 있습니다. 하지만 Band
클래스에는 이미 범위가 적용되어 있으므로 해당 클래스가 or
의 분리 브랜치 중 하나가 됩니다.
런타임 기본 범위 재정의
다음과 같이 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 Driver는 미들웨어를 제공하여 Rack 웹 요청 및 ActiveJob 작업 실행에 필요한 쿼리 캐시를 자동으로 활성화합니다. 관련 지침은 구성 페이지의 Query Cache Rack Middleware(쿼리 캐시 Rack 미들웨어) 섹션을 참조하세요.
쿼리 캐시 미들웨어는 웹 요청 및/또는 작업 외부에서 실행되는 코드에는 적용되지 않습니다.
쿼리 캐시 수동 활성화 중
코드 세그먼트에 대해 쿼리 캐시를 수동으로 활성화하려면 다음 기능을 사용하세요.
Mongo::QueryCache.cache do # ... end
쿼리 캐시를 명시적으로 활성화하거나 비활성화할 수도 있지만, 앞서 설명한 차단 형식을 사용하는 것이 좋습니다.
begin Mongo::QueryCache.enabled = true # ... ensure Mongo::QueryCache.enabled = false end
다음 항목의 결과 캐싱 중: #first
모델 클래스에서 first
메서드를 호출하면 기본 쿼리의 _id
필드를 기준으로 오름차순 정렬이 적용됩니다. 이로 인해 쿼리 캐싱 도중 예상치 못한 동작이 발생할 수 있습니다.
그 예로 모델 클래스에서 all
을(를) 호출한 다음 first
을(를) 호출하면, 두 번째 쿼리가 첫 번째 쿼리에서 캐싱된 결과를 사용할 수 있습니다. 그러나 두 번째 쿼리에 적용되는 정렬 때문에 두 메서드 모두 데이터베이스를 쿼리하고 각자의 결과를 별도로 캐싱합니다.
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