> For the complete documentation index, see [llms.txt](https://docs.mediarithmics.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mediarithmics.io/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/enrich-user-profiles.md).

# Enrich user profiles

Update or delete part of an existing profile without overwriting the whole object.

## Your goal

Change one thing inside a stored profile - add a loyalty card, update a balance, remove an obsolete object - without sending the whole profile and without losing what you did not send.

## Expected outcome

Partial updates that hit exactly the object you intended, and a schema that declares how the platform is supposed to recognise that object.

## When to use a partial update

Use `PARTIAL_UPDATE` or `PARTIAL_DELETE` as the `update_strategy` of a `USER_PROFILE` import when you want **targeted updates on existing profiles without overwriting the whole profile object**. The import mechanics are the same as in [Import profiles](/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/import-profiles.md) - only the strategy changes.

There are two situations, and they need different setup.

{% columns %}
{% column %}

### Arrays of objects

The platform needs to know **which element** of the array you mean. That requires a schema [directive](/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/schema-definition.md#directives) on the object concerned.
{% endcolumn %}

{% column %}

### Plain objects

No array, no ambiguity: `PARTIAL_UPDATE` works with **no directive** needed.
{% endcolumn %}
{% endcolumns %}

## The two directives

Both are declared in the datamart's schema, so [update the schema](/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/schema-definition.md#publishing-a-schema) before relying on them.

| Directive            | Put it on                                          | Use it when                                                                                                           |
| -------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `@UpdateStrategyKey` | The **field** inside the object that identifies it | The object has an "id-like" field. The value of that field in your request identifies which element to update.        |
| `@UpdateValueObject` | The **object** itself                              | The object has no field that can identify it. You send the new value of the object and it overrides the previous one. |

{% hint style="warning" %}
**Use only one of the two directives in a given object.** `@UpdateValueObject` cannot be used with `@UpdateStrategyKey` in the same object.
{% endhint %}

```graphql
type UserProfile {
   compartment_id: String!
   user_account_id: String
   loyalty: [Loyalty]
}

type Loyalty {
   cards: [Cards]
}

type Cards {
   card_id: String! @UpdateStrategyKey
   benefits: String
   last_visit_date: String
}
```

A hierarchy of inner objects is allowed, each level with its own key:

```graphql
# Allowed
type LoyaltyCard {
  card_id: String @UpdateStrategyKey
  benefits: Int
  last_visit_date: String
  other_information: [OtherInformation]
}
type OtherInformation {
  info_id: String @UpdateStrategyKey
}

# Not allowed - two keys in the same object
type LoyaltyCard {
  card_id: String @UpdateStrategyKey
  benefits: Int @UpdateStrategyKey
  last_visit_date: Date
}
```

## What each operation does

Using the `Cards` schema above, with `card_id` as the key.

{% tabs %}
{% tab title="Add to an array" %}
`PARTIAL_UPDATE` with a **new** key value appends the object.

Stored:

```json
{ "loyalty": { "cards": [
  { "card_id": "abc", "benefits": 500, "last_visit_date": "2024-01-01" }
] } }
```

Payload:

```json
{ "loyalty": { "cards": [
  { "card_id": "def", "benefits": 100, "last_visit_date": "2025-01-01" }
] } }
```

Result - both cards:

```json
{ "loyalty": { "cards": [
  { "card_id": "abc", "benefits": 500, "last_visit_date": "2024-01-01" },
  { "card_id": "def", "benefits": 100, "last_visit_date": "2025-01-01" }
] } }
```

{% endtab %}

{% tab title="Update in an array" %}
`PARTIAL_UPDATE` with an **existing** key value updates only the fields you send.

Stored:

```json
{ "loyalty": { "cards": [
  { "card_id": "abc", "benefits": 500, "last_visit_date": "2024-01-01" }
] } }
```

Payload - the key identifies the element, `benefits` is the only change:

```json
{ "loyalty": { "cards": [
  { "card_id": "abc", "benefits": 100 }
] } }
```

Result - `last_visit_date` is untouched:

```json
{ "loyalty": { "cards": [
  { "card_id": "abc", "benefits": 100, "last_visit_date": "2024-01-01" }
] } }
```

{% endtab %}

{% tab title="Delete from an array" %}
`PARTIAL_DELETE` with a key value removes that object from the array.

The same mechanism removes a property inside an array element, rather than the element itself, depending on what you address in the payload.
{% endtab %}

{% tab title="Override an object" %}
With `@UpdateValueObject` on the object, a `PARTIAL_UPDATE` **overrides** the object - array of objects or single object - with the value you send, instead of merging into it.

This is the strategy for objects with no natural identifier, where merging would produce a meaningless mixture of old and new fields.
{% endtab %}

{% tab title="No directive" %}
`PARTIAL_UPDATE` with no directive covers the cases without arrays of objects:

* Updating properties directly on the `UserProfile`.
* Updating a property inside a plain object.
* Overriding a plain object.
  {% endtab %}
  {% endtabs %}

{% hint style="info" %}
**Arrays of scalar values are treated as scalars.** An array such as `[1,2,3]` is replaced as a whole, not merged element by element.
{% endhint %}

## Constraints

**The update request must respect the datamart schema.**

* If a property is in the payload but **not declared in the schema**, the **whole request fails**.
* If a property is already present in the profile but not declared in the schema, it is **not** overwritten by a partial update or delete - and cannot be updated at all except with `FORCE_REPLACE`.
* If the types in the payload do not respect the schema, the whole request fails.

**Properties that cannot be partially updated:**

* A property whose schema declaration uses a directive referencing `[parent]` in its path - for example `@Property(path: "[parent].property")`.
* Computed values: computed fields, ML function results, function results.

## Verify

* The directive is present in the **published** schema, not only in a draft.
* A test update changes only the object you targeted, leaving its siblings intact.
* A test delete removes the object and nothing else.
* The execution's error file is empty - a schema mismatch fails the whole request, so a partial success is not the failure mode to expect here.

## Related pages

<table data-view="cards" data-search="false"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Import profiles</strong></td><td>The import itself, and the other strategies.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/import-profiles.md">Import profiles</a></td></tr><tr><td><strong>Schema definition</strong></td><td>Declaring and publishing the directives.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/schema-definition.md">Schema definition</a></td></tr><tr><td><strong>Enrich users with identifiers</strong></td><td>The identifier equivalent of this job.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/enrich-users-with-identifiers.md">Enrich users with identifiers</a></td></tr></tbody></table>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.mediarithmics.io/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/enrich-user-profiles.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
