Actualiza tus productos con frecuencia

La sub-API de Products te permite realizar actualizaciones parciales de tus productos existentes. Esto es ideal para los datos que cambian con frecuencia, como el precio y la disponibilidad, ya que evita la necesidad de volver a enviar todo el producto para un cambio pequeño. Sin embargo, debes volver a insertar productos con regularidad para asegurarte de que todos los datos de los productos estén sincronizados.

En esta guía, se explica cómo usar el método productinputs.patch para actualizar tus productos.

Requisitos previos

Antes de actualizar un producto, necesitas lo siguiente:

Actualiza detalles específicos del producto

Para cambiar algunos detalles de un producto, como su precio o disponibilidad, sin volver a enviar toda su información, usa el método productInputs.patch.

Puedes especificar qué campos cambias en el parámetro updateMask. updateMask es una lista separada por comas de los campos que deseas actualizar. El método patch se comporta de la siguiente manera:

  • Campos en updateMask y el cuerpo: Estos campos se actualizan con los valores nuevos.
  • Campos en updateMask, pero no en el cuerpo: Estos campos se borran de la entrada del producto.
  • Campos que no están en updateMask: Estos campos no se modifican.
  • Se omitió el parámetro updateMask: Se actualizan todos los campos proporcionados en el cuerpo de la solicitud. Los campos que no se proporcionan en el cuerpo de la solicitud no se borran de la entrada del producto.

A continuación, se muestra un ejemplo de los datos del producto antes de una actualización:

{
  "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"
  }
}

En este ejemplo, se actualizan los campos title y availability de un producto y se borra su campo imageLink. description y price no están en updateMask y permanecerán sin cambios.

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"
    }
 }
}

Una llamada correcta devuelve el recurso ProductInput actualizado. Se actualizan title y availability, y se quita imageLink porque estaba en updateMask, pero no en el cuerpo de la solicitud. Los parámetros description y price permanecen sin cambios, ya que no se incluyeron en 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"
    ],
  }
}

En los siguientes ejemplos de código, se muestra cómo actualizar un producto.

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 = "online~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., "online~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 = "online~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"
   }
}'

Actualiza con atributos personalizados

Puedes actualizar los atributos estándar y personalizados en una sola llamada. Para actualizar un atributo personalizado, antepone customAttributes a su nombre en updateMask.

En este ejemplo, se realizan varias acciones en una sola solicitud:

  • Actualiza directamente el atributo title estándar.
  • Actualiza un atributo personalizado existente (myCustomAttrToBeUpdated).
  • Inserta un atributo personalizado nuevo (myCustomAttrToBeInserted).
  • Borra un atributo personalizado existente (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"
    }
  ]
}

Una solicitud correcta devuelve el ProductInput actualizado que refleja todos los cambios especificados.

Información sobre las actualizaciones de atributos personalizados

Puedes usar el campo customAttributes para actualizar los atributos que definiste. Estos no se asignan a la especificación estándar y se almacenarán como atributos personalizados en el producto final.

Cómo se procesan las actualizaciones de productos

Cuando envías una solicitud de patch, la actualización se aplica a los datos de ProductInput específicos antes de que se aplique cualquiera de las reglas. Esto genera un comportamiento coherente entre la inserción y la actualización de productos.

Así se procesa tu actualización:

  1. Update Input: Tu solicitud de patch modifica el ProductInput específico asociado con la fuente de datos que proporcionaste.

  2. Procesamiento y combinación: Después de que se actualiza la entrada, comienza el procesamiento:

    • Reglas de feeds y fuentes de datos complementarias: Las reglas configuradas en la fuente principal del producto combinan el ProductInput de las fuentes principales y complementarias. Estas reglas pueden cambiar atributos o derivar otros nuevos. Para obtener más información sobre cómo configurar las reglas, consulta el artículo https://support.google.com/merchants/answer/14994083.
    • Otras fuentes de datos: Los datos de otras fuentes (por ejemplo, las mejoras automáticas) también se combinan con la entrada de la fuente de datos principal.
    • Validación: Los datos combinados se validan según las especificaciones de datos de productos y las políticas de compras de Google.
  3. Producto final: El resultado de esta canalización es el recurso Product final procesado que se puede devolver con products.get o products.list. Esta también es la versión del producto que se muestra en Merchant Center y que es apta para aparecer en diferentes destinos.

Debido a este proceso de varios pasos, hay una demora, generalmente de unos minutos, entre el momento en que envías una solicitud de actualización y el momento en que los cambios se reflejan en el recurso Product final que puedes recuperar con products.get.

Ejemplo: Actualización de un producto con una sola entrada principal

Este es el caso de uso más común. Un producto existe en una sola fuente de datos principal y quieres actualizar algunos de sus atributos.

  1. Estado inicial: Existe un producto en~US~SKU12345 en tu fuente de datos principal con title: "Classic T-Shirt" y price: 15.99 USD.
  2. Solicitud de actualización: Envías una solicitud patch para actualizar price a 14.99 USD y configuras availability como out of stock.
  3. Procesamiento:
    • Se actualizó el ProductInput para SKU12345.
  4. Producto final: El Product final ahora tiene title: "Classic T-Shirt", price: 14.99 USD y availability: "out of stock".

Ejemplo: Actualización de un producto con datos y reglas complementarios

En este ejemplo, se muestra cómo las reglas del feed pueden afectar una actualización, lo que provoca que se apliquen algunos cambios y se anulen otros.

  1. Estado inicial:
    • Entrada principal: en~US~SKU12345 tiene title: "Great T-Shirt" y description: "A great short-sleeve t-shirt.".
    • Entrada complementaria: El mismo producto tiene una entrada en una fuente de datos complementaria con title: "Awesome T-Shirt" y description: "An awesome short-sleeve t-shirt.".
    • Regla del feed: Se establece una regla para tomar el title de la fuente de datos complementaria. No hay ninguna regla para description.
    • Resultado: El Product procesado final tiene title: "Awesome T-Shirt" y description: "A great short-sleeve t-shirt.".
  2. Solicitud de actualización: Envías una solicitud patch para actualizar la fuente de datos principal, estableciendo title en "Fantastic T-Shirt" y description en "A fantastic short-sleeve t-shirt.".
  3. Procesamiento:
    • El ProductInput en la fuente de datos principal se actualiza para tener title: "Fantastic T-Shirt" y description: "A fantastic short-sleeve t-shirt.".
    • Se ejecuta la canalización de procesamiento.
    • En el caso de title, la regla del feed indica que el valor de la fuente de datos complementaria (Awesome T-Shirt) tiene prioridad y anula tu actualización.
    • En el caso de description, como no hay ninguna regla de anulación, se usa el valor actualizado de la entrada principal (A fantastic short-sleeve t-shirt.).
  4. Producto final: El título del Product final sigue siendo Awesome T-Shirt (se anuló tu actualización), pero su descripción ahora es A fantastic short-sleeve t-shirt. (se aplicó tu actualización).

Elige entre actualizaciones y fuentes de datos complementarias

Puedes modificar los datos de productos con productinputs.patch o insertando datos en fuentes de datos complementarias. La mejor opción depende de tu estrategia de administración de datos.

Para evitar resultados impredecibles, te recomendamos que no uses productinputs.patch ni fuentes de datos complementarias para administrar los mismos datos de productos para el mismo producto.

A continuación, se incluye una comparación detallada:

Función productinputs.patch (Actualizaciones) Fuentes de datos complementarias
Ideal para Cambios parciales, rápidos y frecuentes en los datos existentes (p. ej., precio y disponibilidad) Datos estratificados lógicamente separados, administración de diferentes atributos por diferentes sistemas o anulaciones complejas basadas en reglas
Mecanismo Modifica un ProductInput existente. Crea un ProductInput nuevo y separado en una fuente de datos complementaria.
Nivel de detalle de los datos Opera en campos específicos de un solo ProductInput. Opera en todo el ProductInput dentro de la fuente complementaria.
Persistencia Los cambios persisten hasta que el mismo ProductInput se reemplaza por un insert completo o por otro patch. Las reglas del feed controlan la persistencia. Puede anular los datos principales de forma indefinida si las reglas le dan prioridad.
Interacción de reglas Se puede usar sin las reglas del feed, ya que actualiza una fuente de datos existente y ProductInput. Requiere configurar explícitamente una regla en la fuente principal para vincular la fuente complementaria.
Configuración de la fuente de datos Operación en una fuente de datos existente. No se necesitan fuentes nuevas. Requiere crear y administrar fuentes de datos complementarias independientes, y vincularlas con reglas de feeds.