`where.missing`과의 연결이 누락된 레코드 찾기

4885 단어 webdevrailsruby
부정을 증명할 수는 없지만 부정을 위해 데이터베이스를 쿼리하는 것은 어떻습니까? 대부분의 경우 데이터를 찾기 위해 쿼리를 작성하지만 데이터가 없는지 찾는 쿼리를 작성하는 것과 반대되는 경우도 있습니다.

원시 SQL의 경우 특정 연결이 없는 레코드를 찾기 위해 LEFT OUTER JOIN 검사와 결합된 null를 사용할 수 있습니다.

용법



Rails에서는 SQL의 동일한 개념을 ActiveRecord로 직접 적용할 수 있습니다.

다음 모델이 있다고 가정해 보겠습니다.

class Account < ApplicationRecord
  has_many :recovery_email_addresses
end


아직 백업 복구 이메일을 설정하지 않은 Account 을(를) 찾으려는 경우 다음 쿼리를 작성할 수 있으며 모든 것이 잘 작동합니다.

Account.left_joins(:recovery_email_addresses).where(recovery_email_addresses: { id: nil })

# SELECT "accounts".* FROM "accounts" LEFT OUTER JOIN "recovery_email_addresses" ON "recovery_email_addresses"."account_id" = "accounts"."id" WHERE "recovery_email_addresses"."id" IS NULL


하지만 좀 장황합니다. Rails 6.1부터 동일한 쿼리를 작성하기 위해 훨씬 깔끔한 속기를 사용할 수 있습니다.

Account.where.missing(:recovery_email_addresses)

# SELECT "accounts".* FROM "accounts" LEFT OUTER JOIN "recovery_email_addresses" ON "recovery_email_addresses"."account_id" = "accounts"."id" WHERE "recovery_email_addresses"."id" IS NULL


이것은 동일한 SQL을 생성하고 읽기가 훨씬 쉽습니다. belongs_to 관계에서도 이 기능을 사용할 수 있습니다.

class Contract < ApplicationRecord
  belongs_to :promiser, class_name: "User"
  belongs_to :promisee, class_name: "User"
  belongs_to :beneficiary, optional: true, class_name: "User"
end

Contract.where.missing(:promiser) # Contracts without a promiser
Contract.where.missing(:promiser, :beneficiary) # Contracts without a promiser AND beneficiary


일반 ActiveRecord 연결 방법과 결합missing할 수도 있습니다.

Contact.where("amount > ?", 1200).where.missing(:promiser)
Contact.where(signed: true).where.missing(:beneficiary)


추가 리소스



레일 저장소: Finding Orphan Records

Rails API 문서: WhereChain#missing

좋은 웹페이지 즐겨찾기