С помощью Products sub-API можно частично обновлять информацию о товарах. Это особенно удобно, если данные часто меняются, например цена или доступность товара. В этом случае вам не придется заново отправлять сведения о товаре, если изменился только один атрибут. Однако мы рекомендуем регулярно добавлять товары заново, чтобы все данные о них были синхронизированы.
В этом руководстве рассказывается, как использовать метод productinputs.patch для обновления информации о товарах.
Требования
Чтобы изменить информацию о товаре, вам понадобится:
- Существующий товар, который нужно обновить. Инструкции по созданию товаров приведены в руководстве Как добавлять товары и управлять ими.
nameисточника данных, к которому относится входной товар (например,accounts/12345/dataSources/67890). Чтобы узнать, как найти этот идентификатор, ознакомьтесь с руководством Как управлять источниками данных API для загрузки товаров.
Как изменить информацию об отдельных товарах
Чтобы изменить некоторые сведения о товаре, например цену или доступность, не отправляя всю информацию заново, используйте метод productInputs.patch.
Вы можете указать, какие поля нужно изменить, в параметре updateMask. updateMask – это список полей, которые нужно обновить, разделенных запятыми. Метод patch работает следующим образом:
- Поля в
updateMaskи теле письма. Эти поля обновляются с новыми значениями. - Поля в
updateMask, но не в теле запроса. Эти поля удаляются из входных данных о товаре. - Поля, не входящие в
updateMask, остаются без изменений. - Параметр
updateMaskне указан. Обновляются все поля, указанные в теле запроса. Поля, не указанные в теле запроса, не удаляются из входных данных о товаре.
Вот пример данных о товаре до обновления:
{
"name": "accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345",
"product": "accounts/{ACCOUNT_ID}/products/en~US~SKU12345",
"offerId": "SKU12345",
"contentLanguage": "en",
"feedLabel": "US",
"productAttributes": {
"title": "Classic Cotton T-Shirt",
"description": "A comfortable, durable, and stylish t-shirt made from 100% cotton.",
"link": "https://www.example.com/p/SKU12345",
"availability": "IN_STOCK",
"price": {
"amountMicros": "15990000",
"currencyCode": "USD"
},
"condition": "NEW",
"gtins": [
"9780007350896"
],
"imageLink": "https://www.example.com/image/SKU12345"
}
}
В этом примере показано, как изменить свойства title и availability товара и удалить его свойство imageLink. description и price не входят в updateMask и останутся без изменений.
PATCH https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?updateMask=productAttributes.title,productAttributes.availability,productAttributes.imageLink&dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
{
"productAttributes": {
"title": "Classic Cotton T-Shirt - New Edition",
"availability": "OUT_OF_STOCK",
"description": "A comfortable T-shirt from premium cotton, newer edition.",
"price": {
"amountMicros": "9990000",
"currencyCode": "USD"
}
}
}
При успешном вызове возвращается обновленный ресурс ProductInput. Значения title и availability обновляются, а imageLink удаляется, поскольку оно было в updateMask, но не в теле запроса. description и price не изменились, так как не были указаны в updateMask.
{
"name": "accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345",
"product": "accounts/{ACCOUNT_ID}/products/en~US~SKU12345",
"offerId": "SKU12345",
"contentLanguage": "en",
"feedLabel": "US",
"productAttributes": {
"title": "Classic Cotton T-Shirt - New Edition",
"description": "A comfortable, durable, and stylish t-shirt made from 100% cotton.",
"link": "https://www.example.com/p/SKU12345",
"availability": "OUT_OF_STOCK",
"price": {
"amountMicros": "15990000",
"currencyCode": "USD"
},
"condition": "NEW",
"gtins": [
"9780007350896"
],
}
}
Ниже приведены примеры кода, в которых показано, как изменить информацию о товаре.
Java
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.protobuf.FieldMask;
import com.google.shopping.merchant.datasources.v1.DataSourceName;
import com.google.shopping.merchant.products.v1.Availability;
import com.google.shopping.merchant.products.v1.Condition;
import com.google.shopping.merchant.products.v1.ProductAttributes;
import com.google.shopping.merchant.products.v1.ProductInput;
import com.google.shopping.merchant.products.v1.ProductInputName;
import com.google.shopping.merchant.products.v1.ProductInputsServiceClient;
import com.google.shopping.merchant.products.v1.ProductInputsServiceSettings;
import com.google.shopping.merchant.products.v1.UpdateProductInputRequest;
import com.google.shopping.type.CustomAttribute;
import shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;
/** This class demonstrates how to update a product input */
public class UpdateProductInputSample {
public static void updateProductInput(Config config, String productId, String dataSourceId)
throws Exception {
// Obtains OAuth token based on the user's configuration.
GoogleCredentials credential = new Authenticator().authenticate();
// Creates service settings using the credentials retrieved above.
ProductInputsServiceSettings productInputsServiceSettings =
ProductInputsServiceSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credential))
.build();
// Creates product name to identify product.
String name =
ProductInputName.newBuilder()
.setAccount(config.getAccountId().toString())
.setProductinput(productId)
.build()
.toString();
// Just productAttributes and customAttributes can be updated
FieldMask fieldMask =
FieldMask.newBuilder()
.addPaths("product_attributes.title")
.addPaths("product_attributes.description")
.addPaths("product_attributes.link")
.addPaths("product_attributes.image_link")
.addPaths("product_attributes.availability")
.addPaths("product_attributes.condition")
.addPaths("product_attributes.gtins")
.addPaths("custom_attributes.mycustomattribute")
.build();
// Calls the API and catches and prints any network failures/errors.
try (ProductInputsServiceClient productInputsServiceClient =
ProductInputsServiceClient.create(productInputsServiceSettings)) {
ProductAttributes attributes =
ProductAttributes.newBuilder()
.setTitle("A Tale of Two Cities")
.setDescription("A classic novel about the French Revolution")
.setLink("https://exampleWebsite.com/tale-of-two-cities.html")
.setImageLink("https://exampleWebsite.com/tale-of-two-cities.jpg")
.setAvailability(Availability.IN_STOCK)
.setCondition(Condition.NEW)
.addGtins("9780007350896")
.build();
// The datasource can be either a primary or supplemental datasource.
String dataSource =
DataSourceName.newBuilder()
.setAccount(config.getAccountId().toString())
.setDatasource(dataSourceId)
.build()
.toString();
UpdateProductInputRequest request =
UpdateProductInputRequest.newBuilder()
.setUpdateMask(fieldMask)
// You can only update product attributes and custom_attributes
.setDataSource(dataSource)
.setProductInput(
ProductInput.newBuilder()
.setName(name)
.setProductAttributes(attributes)
.addCustomAttributes(
CustomAttribute.newBuilder()
.setName("mycustomattribute")
.setValue("Example value")
.build())
.build())
.build();
System.out.println("Sending update ProductInput request");
ProductInput response = productInputsServiceClient.updateProductInput(request);
System.out.println("Updated ProductInput Name below");
// The last part of the product name will be the product ID assigned to a product by Google.
// Product ID has the format `contentLanguage~feedLabel~offerId`
System.out.println(response.getName());
System.out.println("Updated Product below");
System.out.println(response);
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) throws Exception {
Config config = Config.load();
// An ID assigned to a product by Google. In the format
// contentLanguage~feedLabel~offerId
String productId = "en~label~sku123"; // Replace with your product ID.
// Identifies the data source that will own the product input.
String dataSourceId = "{INSERT_DATASOURCE_ID}"; // Replace with your datasource ID.
updateProductInput(config, productId, dataSourceId);
}
}
PHP
use Google\ApiCore\ApiException;
use Google\Protobuf\FieldMask;
use Google\Shopping\Merchant\Products\V1\Availability;
use Google\Shopping\Merchant\Products\V1\Condition;
use Google\Shopping\Merchant\Products\V1\ProductAttributes;
use Google\Shopping\Merchant\Products\V1\Client\ProductInputsServiceClient;
use Google\Shopping\Merchant\Products\V1\ProductInput;
use Google\Shopping\Merchant\Products\V1\UpdateProductInputRequest;
use Google\Shopping\Type\CustomAttribute;
/**
* This class demonstrates how to update a product input.
*/
class UpdateProductInputSample
{
// An ID assigned to a product by Google. In the format
// contentLanguage~feedLabel~offerId
// Please ensure this product ID exists for the update to succeed.
private const PRODUCT_ID = "en~label~sku123";
// Identifies the data source that will own the product input.
// Please ensure this data source ID exists.
private const DATASOURCE_ID = "<INSERT_DATASOURCE_ID>";
/**
* Helper function to construct the full product input resource name.
*
* @param string $accountId The merchant account ID.
* @param string $productInputId The product input ID (e.g., "en~label~sku123").
* @return string The full product input resource name.
*/
private static function getProductInputName(string $accountId, string $productInputId): string
{
return sprintf("accounts/%s/productInputs/%s", $accountId, $productInputId);
}
/**
* Helper function to construct the full data source resource name.
*
* @param string $accountId The merchant account ID.
* @param string $dataSourceId The data source ID.
* @return string The full data source resource name.
*/
private static function getDataSourceName(string $accountId, string $dataSourceId): string
{
return sprintf("accounts/%s/dataSources/%s", $accountId, $dataSourceId);
}
/**
* Updates an existing product input in your Merchant Center account.
*
* @param array $config The configuration array containing the account ID.
* @param string $productId The ID of the product input to update.
* @param string $dataSourceId The ID of the data source.
*/
public static function updateProductInput(
array $config,
string $productId,
string $dataSourceId
): void {
// Gets the OAuth credentials to make the request.
$credentials = Authentication::useServiceAccountOrTokenFile();
// Creates options config containing credentials for the client to use.
$options = ['credentials' => $credentials];
// Creates a ProductInputsServiceClient.
$productInputsServiceClient = new ProductInputsServiceClient($options);
// Construct the full resource name of the product input to be updated.
$name = self::getProductInputName($config['accountId'], $productId);
// Define the FieldMask to specify which fields to update.
// Only 'attributes' and 'custom_attributes' can be specified in the
// FieldMask for product input updates.
$fieldMask = new FieldMask([
'paths' => [
"product_attributes.title",
"product_attributes.description",
"product_attributes.link",
"product_attributes.image_link",
"product_attributes.availability",
"product_attributes.condition",
"product_attributes.gtin",
"custom_attributes.mycustomattribute" // Path for a specific custom attribute
]
]);
// Calls the API and handles any network failures or errors.
try {
// Define the new attributes for the product.
$attributes = new ProductAttributes([
'title' => 'A Tale of Two Cities 3',
'description' => 'A classic novel about the French Revolution',
'link' => 'https://exampleWebsite.com/tale-of-two-cities.html',
'image_link' => 'https://exampleWebsite.com/tale-of-two-cities.jpg',
'availability' => Availability::IN_STOCK,
'condition' => Condition::PBNEW,
'gtins' => ['9780007350896'] // GTIN is a repeated field.
]);
// Construct the full data source name.
// This specifies the data source context for the update.
$dataSource = self::getDataSourceName($config['accountId'], $dataSourceId);
// Create the ProductInput object with the desired updates.
// The 'name' field must match the product input being updated.
$productInput = new ProductInput([
'name' => $name,
'product_attributes' => $attributes,
'custom_attributes' => [ // Provide the list of custom attributes.
new CustomAttribute([
'name' => 'mycustomattribute',
'value' => 'Example value'
])
]
]);
// Create the UpdateProductInputRequest.
$request = new UpdateProductInputRequest([
'update_mask' => $fieldMask,
'data_source' => $dataSource,
'product_input' => $productInput
]);
print "Sending update ProductInput request\n";
// Make the API call to update the product input.
$response = $productInputsServiceClient->updateProductInput($request);
print "Updated ProductInput Name below\n";
// The name of the updated product input.
// The last part of the product name is the product ID (e.g., contentLanguage~feedLabel~offerId).
print $response->getName() . "\n";
print "Updated Product below\n";
// Print the full updated product input object.
print_r($response);
} catch (ApiException $e) {
printf("ApiException caught: %s\n", $e->getMessage());
}
}
/**
* Executes the UpdateProductInput sample.
*/
public function callSample(): void
{
$config = Config::generateConfig();
$productId = self::PRODUCT_ID;
$dataSourceId = self::DATASOURCE_ID;
self::updateProductInput($config, $productId, $dataSourceId);
}
}
// Run the script.
$sample = new UpdateProductInputSample();
$sample->callSample();
Python
"""A module to update a product input."""
from examples.authentication import configuration
from examples.authentication import generate_user_credentials
from google.protobuf import field_mask_pb2
from google.shopping.merchant_products_v1 import Availability
from google.shopping.merchant_products_v1 import Condition
from google.shopping.merchant_products_v1 import ProductAttributes
from google.shopping.merchant_products_v1 import ProductInput
from google.shopping.merchant_products_v1 import ProductInputsServiceClient
from google.shopping.merchant_products_v1 import UpdateProductInputRequest
from google.shopping.type import CustomAttribute
# Fetches the Merchant Center account ID from the authentication examples.
# This ID is needed to construct resource names for the API.
_ACCOUNT_ID = configuration.Configuration().read_merchant_info()
def update_product_input(account_id: str, product_id: str, data_source_id: str):
"""Updates an existing product input for a specific account.
Args:
account_id: The Merchant Center account ID.
product_id: The ID of the product input to update. This ID is assigned by
Google and has the format `contentLanguage~feedLabel~offerId`.
data_source_id: The ID of the data source that owns the product input.
"""
# Obtains OAuth credentials for authentication.
credentials = generate_user_credentials.main()
# Creates a ProductInputsServiceClient instance.
client = ProductInputsServiceClient(credentials=credentials)
# Constructs the full resource name for the product input.
# Format: accounts/{account}/productInputs/{productinput}
name = f"accounts/{account_id}/productInputs/{product_id}"
# Defines the FieldMask to specify which fields of the product input
# are being updated. Only 'attributes' and 'custom_attributes' can be updated.
field_mask = field_mask_pb2.FieldMask(
paths=[
"product_attributes.title",
"product_attributes.description",
"product_attributes.link",
"product_attributes.image_link",
"product_attributes.availability",
"product_attributes.condition",
"product_attributes.gtins",
"custom_attributes.mycustomattribute",
]
)
# Prepares the new attribute values for the product.
attributes = ProductAttributes(
title="A Tale of Two Cities updated",
description="A classic novel about the French Revolution",
link="https://exampleWebsite.com/tale-of-two-cities.html",
image_link="https://exampleWebsite.com/tale-of-two-cities.jpg",
availability=Availability.IN_STOCK,
condition=Condition.NEW,
gtins=["9780007350896"], # GTIN is a repeated field.
)
# Constructs the full resource name for the data source.
# The data source can be primary or supplemental.
# Format: accounts/{account}/dataSources/{datasource}
data_source = f"accounts/{account_id}/dataSources/{data_source_id}"
# Prepares the ProductInput object with the updated information.
product_input_data = ProductInput(
name=name,
product_attributes=attributes,
custom_attributes=[
CustomAttribute(
name="mycustomattribute", value="Example value"
)
],
)
# Creates the UpdateProductInputRequest.
request = UpdateProductInputRequest(
update_mask=field_mask,
data_source=data_source,
product_input=product_input_data,
)
# Sends the update request to the API.
try:
print("Sending update ProductInput request")
response = client.update_product_input(request=request)
print("Updated ProductInput Name below")
# The response includes the name of the updated product input.
# The last part of the product name is the product ID assigned by Google.
print(response.name)
print("Updated Product below")
print(response)
except RuntimeError as e:
# Catches and prints any errors that occur during the API call.
print(e)
if __name__ == "__main__":
# The ID of the product to be updated.
# This ID is assigned by Google and typically follows the format:
# contentLanguage~feedLabel~offerId
# Replace with an actual product ID from your Merchant Center account.
product_id_to_update = "en~label~sku123"
# The ID of the data source that will own the updated product input.
# Replace with an actual data source ID from your Merchant Center account.
data_source_id_for_update = "<INSERT_DATA_SOURCE_ID>"
update_product_input(
_ACCOUNT_ID, product_id_to_update, data_source_id_for_update
)
cURL
curl --location --request PATCH 'https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?updateMask=productAttributes.title,productAttributes.description&dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}' \
--header 'Authorization: Bearer <API_TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
"productAttributes": {
"title": "A Tale of Two Cities",
"description": "A classic novel about the French Revolution"
}
}'
Как обновлять данные с помощью настраиваемых атрибутов
Вы можете обновить как стандартные, так и специальные атрибуты за один вызов. Чтобы обновить настраиваемый атрибут, добавьте к его названию префикс customAttributes в updateMask.
В этом примере в одном запросе выполняется несколько действий:
- Обновляет стандартный атрибут
titleнапрямую. - Изменяет существующий настраиваемый атрибут (
myCustomAttrToBeUpdated). - Вставляет новый настраиваемый атрибут (
myCustomAttrToBeInserted). - Удаляет существующий настраиваемый атрибут (
myCustomAttrToBeDeleted).
PATCH https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?updateMask=productAttributes.title,customAttributes.myCustomAttrToBeInserted,customAttributes.myCustomAttrToBeUpdated,customAttributes.myCustomAttrToBeDeleted&dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
{
"productAttributes": {
"title": "ProductTitle Updated"
},
"customAttributes": [
{
"name": "description",
"value": "A newly updated description."
},
{
"name": "myCustomAttrToBeUpdated",
"value": "myCustomAttrToBeUpdated updated value"
},
{
"name": "myCustomAttrToBeInserted",
"value": "new from update"
}
]
}
При успешном выполнении запроса будет возвращен обновленный объект ProductInput, отражающий все указанные изменения.
Обновление настраиваемых атрибутов
Поле customAttributes можно использовать для обновления атрибутов, которые вы задали самостоятельно. Они не соответствуют стандартной спецификации и будут сохранены как специальные атрибуты конечного товара.
Как обрабатываются обновления товаров
Когда вы отправляете запрос patch, обновление применяется к определенным данным ProductInput до того, как будут применены какие-либо правила. Это обеспечивает единообразие при добавлении и обновлении товаров.
Вот как обрабатывается запрос на обновление:
Изменение входных данных. Ваш запрос
patchизменяет определенныйProductInput, связанный с указанным вами источником данных.Обработка и объединение. После обновления входных данных начинается обработка:
- Правила преобразования фидов и дополнительные источники данных. Правила, настроенные для основного источника данных о товарах, объединяют атрибуты
ProductInputиз основного и дополнительных источников. Эти правила могут изменять атрибуты или создавать новые. Подробнее о том, как настраивать правила преобразования атрибутов… - Другие источники данных. Данные из других источников (например, автоматические улучшения) также объединяются с основным источником данных.
- Проверка. Объединенные данные проверяются на соответствие спецификации сведений о товарах и правилам Google Покупок.
- Правила преобразования фидов и дополнительные источники данных. Правила, настроенные для основного источника данных о товарах, объединяют атрибуты
Конечный продукт. Результатом этого конвейера является конечный обработанный ресурс
Product, который можно вернуть с помощьюproducts.getилиproducts.list. Именно эта версия товара показывается в Merchant Center и может быть представлена в разных сервисах.
Из-за многоэтапного процесса между отправкой запроса на обновление и отражением изменений в конечном ресурсе Product, который можно получить с помощью products.get, проходит некоторое время (обычно несколько минут).
Пример: обновление товара с одним основным источником данных
Это самый распространенный вариант использования. Товар есть в одном основном источнике данных, и вы хотите обновить некоторые его атрибуты.
- Исходное состояние. В основном источнике данных есть товар
en~US~SKU12345с атрибутамиtitle: "Classic T-Shirt"иprice: 15.99 USD. - Запрос на обновление. Вы отправляете запрос
patch, чтобы обновитьpriceдо14.99 USDи задать дляavailabilityзначениеout of stock. - Обработка
- Обновлен
ProductInputдляSKU12345.
- Обновлен
- Финальный продукт. В финальном
Productтеперь естьtitle: "Classic T-Shirt",price: 14.99 USDиavailability: "out of stock".
Пример: обновление товара с помощью дополнительных данных и правил
В этом примере показано, как правила фидов могут повлиять на обновление, в результате чего некоторые изменения будут применены, а другие – отменены.
- Начальное состояние:
- Основной запрос: у
en~US~SKU12345естьtitle: "Great T-Shirt"иdescription: "A great short-sleeve t-shirt.". - Дополнительные входные данные. В дополнительном источнике данных есть запись о том же товаре со значениями
title: "Awesome T-Shirt"иdescription: "An awesome short-sleeve t-shirt.". - Правило фида. Правило настроено так, чтобы брать значение
titleиз дополнительного источника данных. Дляdescriptionнет правила. - Результат. Обработанный файл
Productимеетtitle: "Awesome T-Shirt"иdescription: "A great short-sleeve t-shirt.".
- Основной запрос: у
- Запрос на обновление. Вы отправляете запрос
patchна обновление основного источника данных, задавая для параметраtitleзначение"Fantastic T-Shirt", а для параметраdescription– значение"A fantastic short-sleeve t-shirt.". - Обработка
- Значение
ProductInputв основном источнике данных будет изменено наtitle: "Fantastic T-Shirt"иdescription: "A fantastic short-sleeve t-shirt.". - Запускается конвейер обработки.
- Для атрибута "
title" правило преобразования фида определяет, что значение из дополнительного источника данных (Awesome T-Shirt) имеет приоритет и переопределяет ваше обновление. - Для
description, поскольку нет переопределяющего правила, используется обновленное значение из основного источника (A fantastic short-sleeve t-shirt.).
- Значение
- Итоговый товар. Название товара
Productосталось прежним (Awesome T-Shirt), а описание изменилось наA fantastic short-sleeve t-shirt..
Как выбрать между обновлениями и дополнительными источниками данных
Изменить данные о товарах можно с помощью productinputs.patch или добавив информацию в дополнительные источники данных. Выбор зависит от вашей стратегии управления данными.
Чтобы избежать непредсказуемых результатов, мы рекомендуем не использовать одновременно атрибут "дополнительный источник данных" productinputs.patch и дополнительные источники данных для управления сведениями об одном и том же товаре.
Ниже приведено подробное сравнение.
| Функция | productinputs.patch (Обновления) |
Дополнительные источники данных |
|---|---|---|
| Кому подойдет | Быстрое, частое и частичное изменение существующих данных (например, цены или наличия). | Наложение логически разделенных данных, управление разными атрибутами с помощью разных систем или сложные переопределения на основе правил. |
| Механизм | Изменяет существующий объект ProductInput. |
Создает новый отдельный атрибут "цена со скидкой" ProductInput в дополнительном источнике данных. |
| Детализация данных | Работает с определенными полями одного объекта ProductInput. |
Относится ко всему значению ProductInput в дополнительном источнике. |
| Постоянство | Изменения сохраняются, пока ProductInput не будет перезаписан полным insert или другим patch. |
Сохранение контролируется правилами преобразования фидов. Может неограниченно долго заменять основные данные, если это предусмотрено правилами. |
| Взаимодействие с правилами | Можно использовать без правил фида, так как он обновляет существующий источник данных и ProductInput. |
Требуется явная настройка правила в основном источнике для связывания дополнительного источника. |
| Настройки источника данных | Работает с существующим источником данных. Новые источники не нужны. | Требуется создать и настроить отдельные дополнительные источники данных и связать их с помощью правил фидов. |