필드 마스크를 사용한 업데이트

Google Ads API에서는 필드 마스크를 사용하여 업데이트가 이루어집니다. 필드 마스크에는 업데이트와 함께 변경하려는 모든 필드가 나열되며, 필드 마스크에 없는 지정된 필드는 서버로 전송되더라도 무시됩니다.

FieldMaskUtil

필드 마스크를 생성하는 데 권장되는 방법은 기본 제공되는 필드 마스크 유틸리티를 사용하는 것입니다. 이 유틸리티를 사용하면 많은 특정 세부정보를 숨기고 항목 필드의 변경사항을 모니터링하여 필드 마스크를 자동으로 생성할 수 있습니다.

캠페인을 업데이트하기 위해 필드 마스크를 생성하는 방법은 다음과 같습니다.

campaign = client.resource.campaign
campaign.resource_name = client.path.campaign(customer_id, campaign_id)

mask = client.field_mask.with campaign do
  campaign.status = :PAUSED
  campaign.network_settings = client.resource.network_settings do |ns|
    ns.target_search_network = false
  end
end

코드는 먼저 빈 캠페인 객체를 만든 다음 리소스 이름을 설정하여 업데이트 중인 캠페인의 API에 알립니다.

이 예시에서는 캠페인에서 client.field_mask.with 메서드를 사용하여 업데이트를 포함하는 블록을 시작합니다. 이 블록이 끝날 때 유틸리티는 블록 이후 캠페인의 현재 상태를 차단 전 캠페인의 초기 상태와 비교하고 변경된 필드를 열거하는 필드 마스크를 자동으로 생성합니다. 다음과 같이 muts 호출을 위해 구성할 때 이 필드 마스크를 작업에 제공할 수 있습니다.

operation = client.operation.campaign
operation.update = campaign
operation.update_mask = mask

이 방법은 복잡한 작업을 실행하고 모든 단계를 세밀하게 제어하려는 경우에 권장됩니다. 하지만 대부분의 경우 더 간단한 Ruby 라이브러리 유틸리티를 사용할 수 있습니다.

operation = client.operation.update_resource.campaign do |c|
  c.status = :PAUSED
  c.network_settings = client.resource.network_settings do |ns|
    ns.target_search_network = false
  end
end

이 메서드는 자동으로 빈 캠페인 리소스를 새로 만들고, 블록 내에서 변경한 내용을 기반으로 필드 마스크를 구성하고, 업데이트 작업을 빌드하고, updateupdate_mask가 이미 채워진 최종 작업을 반환합니다. campaign 메서드에 캠페인을 전달하여 캠페인의 시작 상태를 지정할 수도 있습니다. 이 패턴은 업데이트 작업을 지원하는 모든 리소스에 적용됩니다.

수동으로 마스크 만들기

라이브러리 유틸리티를 사용하지 않고 필드 마스크를 처음부터 만들려면 먼저 Google::Protobuf::FieldMask를 만든 후 변경하려는 모든 필드의 이름으로 채워진 배열을 만들고 마지막으로 배열을 필드 마스크의 path 필드에 할당합니다.

mask = Google::Protobuf::FieldMask.new
mask.path = ["status", "name"]

메시지 필드 및 하위 필드 업데이트

MESSAGE 필드에는 하위 필드가 있거나 (예: target_cpa_micros, cpc_bid_ceiling_micros, cpc_bid_floor_micros 3개가 포함된 MaximizeConversions) 아예 없을 수도 있습니다 (예: ManualCpm).

정의된 하위 필드가 없는 메시지 필드

하위 필드가 정의되지 않은 MESSAGE 필드를 업데이트할 때는 앞에서 설명한 대로 FieldMaskUtil을 사용하여 필드 마스크를 생성합니다.

정의된 하위 필드가 있는 메시지 필드

메시지의 하위 필드를 명시적으로 설정하지 않고 하위 필드로 정의된 MESSAGE 필드를 업데이트하는 경우 필드 마스크를 처음부터 만든 이전 예시와 유사하게 변경 가능한 MESSAGE 하위 필드를 각각 FieldMask에 수동으로 추가해야 합니다.

일반적인 예로 새 입찰 전략의 필드를 설정하지 않고 캠페인의 입찰 전략을 업데이트하는 경우가 있습니다. 다음 예에서는 입찰 전략의 하위 필드를 설정하지 않고 MaximizeConversions 입찰 전략을 사용하도록 캠페인을 업데이트하는 방법을 보여줍니다.

이 예에서는 FieldMaskUtil의 기본 제공 비교를 사용해도 의도한 목표를 달성할 수 없습니다.

다음 코드는 maximize_conversions를 포함하는 필드 마스크를 생성합니다. 하지만 Google Ads API에서는 실수로 필드를 지우고 FieldMaskError.FIELD_HAS_SUBFIELDS 오류를 방지하기 위해 이 동작을 허용하지 않습니다.

# Creates a campaign with the proper resource name.
campaign = client.resource.campaign do |c|
  c.resource_name = client.path.campaign(customer_id, campaign_id)
end

# Update the maximize conversions field within the update block, so it's
# captured in the field mask
operation = client.operation.update_resource.campaign(campaign) do |c|
  c.maximize_conversions = client.resource.maximize_conversions
end

# Sends the operation in a mutate request that will result in a
# FieldMaskError.FIELD_HAS_SUBFIELDS error because empty MESSAGE fields cannot
# be included in a field mask.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
)

다음 코드는 하위 필드를 설정하지 않고 MaximizeConversions 입찰 전략을 사용하도록 캠페인을 올바르게 업데이트하는 방법을 보여줍니다.

# Create the operation directly from the campaign's resource name. Don't do
# anything in the block so that the field mask is empty. You could modify other
# fields in this block, just not the message field that is intended to have a
# blank subfield. We'll add that below.
campaign_resource_name = client.path.campaign(customer_id, campaign_id)
operation = client.operation.update_resource.campaign(campaign_resource_name) {}

# Manually add the maximize conversions subfield to the field mask so the API
# knows to clear it.
operation.update_mask.paths << "maximize_conversions.target_cpa_micros"

# This operation succeeds.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
)

필드 지우기

일부 필드는 명시적으로 지울 수 있습니다. 이전 예와 마찬가지로 이러한 필드를 필드 마스크에 명시적으로 추가해야 합니다. 예를 들어 MaximizeConversions 입찰 전략을 사용하는 캠페인이 있고 target_cpa_micros 필드가 0보다 큰 값으로 설정되어 있다고 가정해 보겠습니다.

다음 코드가 실행되지만 maximize_conversions.target_cpa_micros가 필드 마스크에 추가되지 않으므로 target_cpa_micros 필드가 변경되지 않습니다.

# Create a campaign object representing the campaign you want to change.
campaign = client.resource.campaign do |c|
  c.resource_name = client.path.campaign(customer_id, campaign_id)
end

# The field mask in this operation will include 'maximize_conversions',
# but not 'maximize_conversions.target_cpa_micros', so it will result in an
# error.
operation = client.operation.update_resource.campaign(campaign) do |c|
  c.maximize_conversions = client.resource.maximize_conversions do |mc|
    mc.target_cpa_micros = 0
  end
end

# Operation will fail since field mask is incorrect.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
end

다음 코드는 MaximizeConversions 입찰 전략에서 target_cpa_micros 필드를 적절하게 삭제하는 방법을 보여줍니다.

# Create a campaign including the maximize conversions fields right away, since
# we're going to manually add them to the field mask.
campaign = client.resource.campaign do |c|
  c.resource_name = client.path.campaign(customer_id, campaign_id)
  c.maximize_conversions = client.resource.maximize_conversions do |mc|
    mc.target_cpa_micros = 0
  end
end

# Create the operation with an empty field mask. You may add a block here with
# other changes that will automatically get added to the field mask.
operation = client.operation.update_resource.campaign(campaign) {}

# Add the field to the field mask so the API knows to clear it.
operation.update_mask.paths << 'maximize_conversions.target_cpa_micros'

# Operation will succeed since we specified the correct field mask.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
end

Google Ads API protocol buffers에서 optional로 정의된 필드에는 '잘못된' 코드가 정상적으로 작동합니다. 하지만 target_cpa_microsoptional 필드가 아니므로 '잘못된' 코드는 target_cpa 필드를 지우도록 입찰 전략을 업데이트하지 않습니다.