--- title: Field mapping description: Turn your source field names and shapes into canonical catalog fields — renaming, transforming, splitting and defaulting, with a dry run before you save. Applies to feeds and to API pushes alike. slug: indexing/mapping docKind: reference hub: luigisbox-ai --- Source data carries its own names and shapes: `name` instead of `@title`, `price_with_vat` as a string instead of `price` as a number, availability as `"in stock"` instead of `1`. A **mapping** is a small declarative document that says which source field becomes which catalog field, and what to do to the value on the way. Nothing about your export or your payloads has to change. Mapping sits in front of both ways in: content arriving from a [feed](/indexing/feeds/) and content pushed over the [Content API](/indexing/content-api/) are mapped the same way, by object type. Mappings are usually written with your Luigi's Box implementation contact during onboarding. This page is for reading the one you have, and for changing it yourself over the [feed management API](/indexing/feed-management-api/). ## Shape A mapping is a JSON object of `source → target`: ```json { "name": "@title", "product_id": "@id", "price_with_vat": "price | to_f", "stock_status": "availability | translate('in stock', 1, 'out of stock', 0) | to_i" } ``` - **The key selects a field on the incoming record.** Dot-paths reach into nested structures; `*` matches a group of names. - **The value is a target spec**: an optional target field name, then any number of `|`-chained transforms. Fields you do not mention pass through unchanged, so a mapping only needs to describe what differs. :::note[A rename moves the field] Mapping `name` to `@title` leaves no `name` behind — the field is moved, not copied. To keep the original as well, list both targets (see [Writing to several fields](#writing-to-several-fields)). ::: ## Renaming The target spec is the new name: ```json { "name": "@title", "product_id": "@id", "link": "url", "img": "image_url" } ``` ## Transforming Chain transforms after a `|`. They run left to right. ```json { "price_with_vat": "price | to_f", "description": "description | decode_html_entities", "link": "url | strip_all_parameters" } ``` To transform a field **in place**, without renaming it, omit the target name and start with the pipe: ```json { "price": "| to_f", "title": "| decode_html_entities" } ``` Applied to a list, a transform runs on each element. ### Available transforms **Type conversion.** A field's first value fixes its type for the whole catalog, and a price stored as text cannot be range-filtered. | Transform | Effect | |---|---| | `to_f` | To a number. `0.0` if the value is missing or unparseable. | | `to_i` | To a whole number, truncating decimals. `0` on failure. | | `to_s` | To text. Empty string for a missing value. | | `to_bool` | To `true`/`false`. Accepts `1`/`0`, `y`/`n`, `yes`/`no`, `t`/`f`, `true`/`false`. | | `to_date` | To an ISO date, `YYYY-MM-DD`. | | `to_time` | To an ISO 8601 timestamp. | | `json_parse` | Parse a JSON string into real structure. | **Text.** | Transform | Effect | |---|---| | `replace('find', 'with')` | Replace every occurrence | | `prefix('text')` / `append('text')` | Add text at the start or end | | `capitalize` | First character upper, rest lower | | `split_by_separator('/')` | Split into a list, trimming each part | | `decode_html_entities` | Decode entities and strip HTML tags | | `strip_all_parameters` | Drop the query string from a URL | | `translate('a', 1, 'b', 2)` | Map values through a lookup table; unmatched values pass through | **Lists.** | Transform | Effect | |---|---| | `to_array` | Wrap a single value in a list | | `first` / `last` | Keep only the first or last element | | `drop_last` | Drop the last element | | `flatten` | Flatten one level of nesting | | `uniq` | Remove duplicates, keeping order | | `unpack_array` | Unwrap a one-element list to the value itself | | `values` | Take a nested object's values as a list | **Numbers.** | Transform | Effect | |---|---| | `min` / `max` | The smallest or largest of the value, optionally against a second value | `prefix` is how you build typed identities from a bare key: ```json { "product_id": "@id | prefix('product/')" } ``` A source `product_id` of `sku-1001` becomes `@id: "product/sku-1001"` — the form [identity](/concepts/identifiers/#catalog-object-identity) requires. ### Referencing another field A transform argument beginning with `@` reads another field from the same record: ```json { "sale_price": "price | min(@list_price)" } ``` If the referenced field is absent, the transform is skipped rather than failing the record. ## Writing to several fields Give a list of target specs to write one source field to several places — including back to its own name, which is how you keep a field while also deriving from it: ```json { "name": ["@title", "name"], "category_path": ["@category | split_by_separator(' > ') | last", "category_path"] } ``` ## Nested sources Dot-paths reach into structure: ```json { "attributes.color": "color", "shipping.price": "shipping_price | to_f" } ``` A `.` as the target name spreads an object's keys into the record itself, which flattens a nested block: ```json { "params": "." } ``` Applied to a record: ```json // before { "params": { "material": "cotton", "fit": "regular" } } // after { "material": "cotton", "fit": "regular" } ``` ## Wildcards `*` matches a group of source names, and `\1` in the target inserts what it matched: ```json { "custom_*": "\\1" } ``` `custom_color` becomes `color`, `custom_fit` becomes `fit`. Useful for feeds that prefix every extra attribute. ## Defaults An `@defaults` block fills in fields the record does not have. It runs before the rest of the mapping, and it never overwrites a value that is already present: ```json { "@defaults": { "availability": 1, "currency": "EUR" }, "price_with_vat": "price | to_f" } ``` Values here can reference other fields with `@`, and a reference to an absent field is skipped. ## Try it before you save `POST /catalog/v1/{catalog_id}/mappings/validate` applies a mapping to a sample record and returns the result. Nothing is stored. ```bash curl -X POST 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/mappings/validate' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "mapping": { "name": "@title", "product_id": "@id | prefix(\"product/\")", "price_with_vat": "price | to_f", "stock_status": "availability | translate(\"in stock\", 1, \"out of stock\", 0) | to_i" }, "sample": { "product_id": "sku-1001", "name": "Blue Cotton T-Shirt", "price_with_vat": "29.90", "stock_status": "in stock" } }' ``` The response is the mapped record: ```json { "result": { "@id": "product/sku-1001", "@title": "Blue Cotton T-Shirt", "price": 29.9, "availability": 1 } } ``` Use one record copied verbatim from your real feed as the sample. A hand-written example can differ from the export in exactly the detail the mapping has to handle. ## Managing mappings | Operation | Endpoint | |---|---| | List | `GET /catalog/v1/{catalog_id}/mappings` | | Create | `POST /catalog/v1/{catalog_id}/mappings` | | Read | `GET /catalog/v1/{catalog_id}/mappings/{mapping_id}` | | Update | `PATCH /catalog/v1/{catalog_id}/mappings/{mapping_id}` | | Delete | `DELETE /catalog/v1/{catalog_id}/mappings/{mapping_id}` | A mapping belongs to a catalog and an object type (`catalog_type`), and a feed points at one by `mapping_id`. See [Feed management API](/indexing/feed-management-api/). Changing a mapping affects records processed **after** the change. To re-apply it to your whole catalog, reset the feed's fingerprints and resynchronize — see [Forcing a full resend](/indexing/feed-management-api/#forcing-a-full-resend). ## See also - [Catalog object model](/concepts/catalog-object-model/) — what you are mapping to - [Feeds overview](/indexing/feeds/) — source fields and catalog fields - [Feed management API](/indexing/feed-management-api/) — attaching a mapping to a feed - [Catalog metadata](/indexing/catalog-metadata/) — checking the types you produced - [Feed troubleshooting](/indexing/feeds/troubleshooting/)