Маски полей

В Google Ads API обновления выполняются с помощью маски поля. Маска поля (google.protobuf.FieldMask) содержит список путей к полям в snake_case, которые вы хотите изменить. Все указанные поля, которых нет в маске, игнорируются, даже если они отправлены на сервер.

Утилита FieldMasks

Рекомендуемый способ создания масок полей в клиентской библиотеке Java – использование встроенного служебного класса FieldMasks, который позволяет создавать маски полей из измененного объекта, а не с нуля.

Вот пример обновления кампании:

// Creates a Campaign object with the proper resource name and any other
// changes.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .setStatus(CampaignStatus.PAUSED)
        .build();

// Constructs an operation that updates the campaign, using the
// FieldMasks.allSetFieldsOf utility to derive the update mask. This mask tells
// the Google Ads API which attributes of the campaign you want to change.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

В этом примере сначала создается пустой объект Campaign и задается название его ресурса, чтобы API знал, какая кампания обновляется.

Затем в примере вызывается метод FieldMasks.allSetFieldsOf() для кампании, чтобы автоматически создать маску поля, которая перечисляет все заданные поля. Вы можете передать возвращенную маску непосредственно в вызов обновления.

Если вам нужно обновить несколько полей в существующем объекте, используйте метод FieldMasks.compare() следующим образом:

// Assumes existingCampaign was retrieved from a previous API call.

// Creates a new campaign based on the existing campaign and updates the
// campaign by setting its status to paused.
Campaign campaignToUpdate =
    existingCampaign.toBuilder()
        .setStatus(CampaignStatus.PAUSED)
        .build();

// Constructs an operation that updates the campaign, using the
// FieldMasks.compare utility to derive the update mask. This mask tells the
// Google Ads API which attributes of the campaign you want to change.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaignToUpdate)
        .setUpdateMask(FieldMasks.compare(existingCampaign, campaignToUpdate))
        .build();

// Sends the operation in a mutate request.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

Чтобы создать маску поля с нуля, создайте конструктор FieldMask и добавьте snake_case название каждого поля, которое вы хотите изменить:

FieldMask fieldMask =
    FieldMask.newBuilder()
        .addPaths("status")
        .addPaths("name")
        .build();

Обновление полей сообщений и их подполей

Поля MESSAGE могут иметь подполя (например, MaximizeConversions, у которого есть подполя target_cpa_micros, cpc_bid_ceiling_micros и cpc_bid_floor_micros) или не иметь их (например, ManualCpm).

Поля сообщений без определенных подполей

При обновлении поля MESSAGE, для которого не определены подполя, используйте утилиту FieldMasks, чтобы создать маску поля, как описано в предыдущем разделе.

Поля сообщений с определенными подполями

При обновлении поля MESSAGE, у которого есть определенные подполя, без явного указания какого-либо из подполей в этом сообщении, вы должны вручную добавить каждое из изменяемых подполей MESSAGE в FieldMask, как при создании маски поля с нуля.

Например, вы можете обновить стратегию назначения ставок в кампании (поле oneofcampaign_bidding_strategy), не задав ни одного поля в новой стратегии. В примере ниже показано, как обновить кампанию, чтобы использовать стратегию назначения ставок MaximizeConversions, не задавая никаких дополнительных полей.

В этом случае использование только методов allSetFieldsOf() и compare() класса FieldMasks не позволит достичь желаемой цели.

В примере ниже создается маска поля, которая включает maximize_conversions. Однако Google Ads API не позволяет использовать пути сообщений верхнего уровня с подполями в маске обновления (чтобы предотвратить случайную очистку подполей) и возвращает ошибку FieldMaskError.FIELD_HAS_SUBFIELDS.

// Creates a campaign with the proper resource name and an empty
// MaximizeConversions field.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .setMaximizeConversions(MaximizeConversions.newBuilder().build())
        .build();

// Constructs an operation using FieldMasks.allSetFieldsOf to derive the update
// mask. The field mask includes 'maximize_conversions', which produces a
// FieldMaskError.FIELD_HAS_SUBFIELDS error.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request that results in a
// FieldMaskError.FIELD_HAS_SUBFIELDS error because empty MESSAGE fields with
// subfields cannot be included directly in a field mask.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

В примере ниже показано, как правильно обновить кампанию, чтобы использовать стратегию назначения ставок MaximizeConversions, не задавая ее подполя. Подробнее о назначении стандартных и пакетных стратегий назначения ставок…

// Creates a Campaign object with the proper resource name.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .build();

// Creates a field mask from the campaign and adds the mutable subfield
// ('maximize_conversions.target_cpa_micros') on the MaximizeConversions
// bidding strategy to the field mask. Because this subfield is included in the
// field mask while excluded from the campaign object, the Google Ads API
// switches the campaign's bidding strategy oneof to MaximizeConversions with
// target_cpa_micros unset.
FieldMask fieldMask =
    FieldMasks.allSetFieldsOf(campaign).toBuilder()
        .addPaths("maximize_conversions.target_cpa_micros")
        .build();

// Creates an operation to update the campaign with the specified fields.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(fieldMask)
        .build();

Очистить поля

Некоторые поля можно очистить явным образом. Как и в предыдущем примере, вы должны явно добавить эти поля в маску поля, оставив их неустановленными в объекте сообщения. Например, у вас есть кампания, в которой используется стратегия назначения ставок MaximizeConversions, а в поле target_cpa_micros задано значение больше 0.

Следующий код выполняется, но maximize_conversions.target_cpa_micros не будет очищен, как предполагалось:

// Creates a campaign with the proper resource name and a MaximizeConversions
// object with target_cpa_micros set to 0L.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .setMaximizeConversions(
            MaximizeConversions.newBuilder().setTargetCpaMicros(0L).build())
        .setStatus(CampaignStatus.PAUSED)
        .build();

// Constructs an operation using FieldMasks.allSetFieldsOf to derive the
// update mask.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request that does not clear the field
// cleanly.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

В следующем примере показано, как правильно очистить поле target_cpa_micros в стратегии назначения ставок MaximizeConversions.

// Creates a Campaign object with the proper resource name.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .build();

// Constructs a field mask from the campaign and adds the
// 'maximize_conversions.target_cpa_micros' field to the field mask, which
// clears this field from the bidding strategy without impacting any other
// fields on the bidding strategy.
FieldMask fieldMask =
    FieldMasks.allSetFieldsOf(campaign).toBuilder()
        .addPaths("maximize_conversions.target_cpa_micros")
        .build();

// Creates an operation to update the campaign with the specified field.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(fieldMask)
        .build();