# User profiles import

Use this feature to UPSERT or DELETE [user profiles](https://developer.mediarithmics.io/user-points/user-profiles) in your datamart.&#x20;

## How-to

Use the [bulk import ](https://developer.mediarithmics.io/data-streams/data-ingestion/bulk-processing)endpoints to create a [document import](https://developer.mediarithmics.io/data-streams/data-ingestion/bulk-processing/..#document-import) with the`USER_PROFILE`document type and `APPLICATION_X_NDJSON` mime type. Only `ndjson` data is supported for user profiles.

{% hint style="success" %}
You can, of course, upload multiple user profiles at once. Note the uploaded data is in `ndjson` and not `json`. That means the different profiles are not separated by commas, but by a line separator `\n`
{% endhint %}

Then, create an[ execution ](https://developer.mediarithmics.io/data-streams/data-ingestion/bulk-processing/..#create-an-execution)with your user profile import commands formatted in `ndjson` .

### User profile import command

Each line in the uploaded file can have the following properties:

| property          | type                   | description                                                                                                                                                                                                          |
| ----------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| operation         | Enum                   | Either `UPSERT` or `DELETE`                                                                                                                                                                                          |
| compartment\_id   | String (Optional)      | The Compartment ID, acting as a user [identifier ](https://developer.mediarithmics.io/user-points#user-identifiers)in correlation with `user_account_id`                                                             |
| user\_account\_id | String (Optional)      | The User Account ID, acting as an [identifier](https://developer.mediarithmics.io/user-points/user-profiles#user-profile-object) in correlation with `compartment_id`                                                |
| email\_hash       | String (Optional)      | The Email Hash, acting as an [identifier](https://developer.mediarithmics.io/user-points#user-identifiers)                                                                                                           |
| user\_agent\_id   | String (Optional)      | The User Agent ID, acting as an [identifier](https://developer.mediarithmics.io/user-points#user-identifiers)                                                                                                        |
| update\_strategy  | Enum (Optional)        | <p>Only considered when operation == <code>UPSERT</code> <br>Values are <code>PARTIAL\_UPDATE</code>, <code>PARTIAL\_DELETE</code>, <code>FORCE\_REPLACE</code></p>                                                  |
| user\_profile     | JSON Object (Optional) | <p>Mandatory when operation == UPSERT.</p><p></p><p>JSON Object representing the User Profile. Please refer to the <a href="../../../../user-points/user-profiles">user profile object</a> for more information.</p> |

{% hint style="warning" %}
When importing profiles with identifiers, only one identifier is allowed per line. For example, you shouldn't specify the user agent ID if the Email Hash is already used in a line.&#x20;
{% endhint %}

### Example

First create the document import using the call below. You can also reuse a document import that was previously created

```bash
curl -X POST \
  https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
  -H 'Authorization: <YOUR_API_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{
	"document_type": "USER_PROFILE",
	"mime_type": "APPLICATION_X_NDJSON",
	"encoding": "utf-8",
	"name": "<YOUR_DOCUMENT_IMPORT_NAME>"
}'
```

Each user profile import you do will be a new execution of the document import created. Here is an example :

```bash
# Here we use the combination of compartment_id and user_account_id acting as identifier
curl -X POST \
  https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
  -H 'Authorization: <API_TOKEN>' \
  -H 'Content-Type: application/x-ndjson' \
  -d '{ 
        "operation": "UPSERT",
        "compartment_id": "<COMPARTMENT_ID>", 
        "user_account_id": "<USER_ACCOUNT_ID>",
        "user_profile": {
              this": "is",
              "a":"test"
        }
      }'
```

## Available update strategies when updating existing user profiles

When doing an `UPSERT` if you want to update existing profiles in your datamart you should use the `update_strategy` property.

### PARTIAL\_UPDATE and PARTIAL\_DELETE

If you wish to perform targeted updates on existing profiles without overwriting the whole existing user profile object, you should use the `PARTIAL_UPDATE` or `PARTIAL_DELETE` values of the `update_strategy` property.&#x20;

There are 2 main usage for these strategies :&#x20;

1. **Dealing with arrays of objects**

If you're dealing with arrays of objects, these strategies work together with two [directives](https://developer.mediarithmics.io/schema#directives) that should be defined on the schema of the datamart you are working on. In this case, you should first [update the schema](https://developer.mediarithmics.io/schema/defining-your-schema) in order to include the directives.&#x20;

If you want to make targeted updates on a object that has "id-like" field that can be used to identify the object, use  `@UpdateStrategyKey`

* Mark the **field** with the directive inside the given object you would like to make updates on. The field that has the directive will serve to identify the given object based on the value of this field in the update request.&#x20;
  * For example of where the directive is needed, see use cases #1 to #5 below.

If you want to make targeted updates on a object that does not have a field that can be used to identify the object you should use `@UpdateValueObject`

* Mark the **object** with the directive : send in the payload with the new value of the object and it will override the previous value.
  * For example of where the directive is needed, see use case #6 and #7 below.

{% hint style="warning" %}
**You should use only one of the directive in a given object**
{% endhint %}

2. **Dealing with objects**

When there are no arrays of objects involved, you can still use the `PARTIAL_UPDATE` but the no directive is necessary. For examples, check use cases #8 to #10.

#### **#1 - Add an object in array of objects - PARTIAL\_UPDATE** using the `@UpdateStrategyKey` directive

```graphql
# Schema extract

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

```json
// Existing profile
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      {
        "card_id": "abc",
        "benefits": 500,
        "last_visit_date": "2024-01-01"
      }
    ]
  }
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [ //adding a new cards object
      {
        "card_id": "def",
        "benefits": 100,
        "last_visit_date": "2025-01-01"
      }
    ]
  }
}

//New profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [ // the cards object contains both cards
      {
        "card_id": "abc",
        "benefits": 500,
        "last_visit_date": "2024-01-01"
      },
      {
        "card_id": "def",
        "benefits": 100,
        "last_visit_date": "2025-01-01"
      }
    ]
  }
}
```

#### **#2 - Update a property in an array of objects - PARTIAL\_UPDATE** using the `@UpdateStrategyKey` directive

```graphql
# Schema extract

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

```json
// Existing profile
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      {
        "card_id": "abc",
        "benefits": 500,
        "last_visit_date": "2024-01-01"
      }
    ]
  }
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [ //request changing the benefits value of the existing card
      {
        "card_id": "abc", // value of the field marked with @UpdateStrategyKey of the inner object to update
        "benefits": 100
      }
    ]
  }
}

//New profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [ // 
      {
        "card_id": "abc",
        "benefits": 100, // value has been updated
        "last_visit_date": "2024-01-01"
      }
    ]
  }
}
```

{% hint style="info" %}
Remark : arrays of scalar values are treated as scalars. See example below :
{% endhint %}

```json
// Extract of existing profile
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "my_array_of_scalars": [1,2,3],
  ...
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "my_array_of_scalars": [4,5,6],
  ...
}

//New profile
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "my_array_of_scalars": [4,5,6], // the value of the property has been replaced by the new value
  ...
}

```

#### **#3 - Delete a property inside an array of objects - PARTIAL\_UPDATE** using the `@UpdateStrategyKey` directive

```graphql
# Schema extract

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

For a non mandatory value you can also set a given field to `null` (but not an object directly). For instance in the previous example you could have done the following :&#x20;

```json
// Existing profile
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      {
        "card_id": "abc",
        "benefits": 500,
        "last_visit_date": "2024-01-01"
      }
    ]
  }
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [ 
      {
        "card_id": "abc",
        "benefits": null // set the value to null
      }
    ]
  }
}

//New profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [ // benefits value has been cleared
      {
        "card_id": "abc",
        "last_visit_date": "2024-01-01"
      }
    ]
  }
}
```

#### **#4 - Update object inside an array and add new object - PARTIAL\_UPDATE** using the `@UpdateStrategyKey` directive

```graphql
# Schema extract

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

```json
// Existing profile
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      {
        "card_id": "abc",
        "benefits": 500,
        "last_visit_date": "2024-01-01"
      }
    ]
  }
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [ 
      {
        "card_id": "abc",
        "benefits": 100 //updating exsisting object
      },
      {
        "card_id": "def", //adding a new object
        "benefits": 600,
        "last_visit_date": "2025-01-01"
      }
    ]
  }
}

//New profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      {
        "card_id": "abc",
        "benefits": 100, // value has been updated
        "last_visit_date": "2024-01-01"
      },
      {
        "card_id": "def", // object has been added
        "benefits": 600,
        "last_visit_date": "2025-01-01"
      }
    ]
  }
}
```

#### **#5 - Delete an object in an array of objects - PARTIAL\_DELETE** using the `@UpdateStrategyKey` directive

```graphql
# Schema extract

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

```json
//Existing profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      {
        "card_id": "abc",
        "benefits": 100,
        "last_visit_date": "2024-01-01"
      },
      {
        "card_id": "def",
        "benefits": 600,
        "last_visit_date": "2025-01-01"
      }
    ]
  }
}

//Profile in update payload with update_strategy == PARTIAL_DELETE
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [ 
      {
        "card_id": "abc" // value of the field marked with @UpdateStrategyKey of the inner object to delete
      }
    ]
  }
}

//New profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [ // the card with card_id = "abc" has been deleted
      {
        "card_id": "def",
        "benefits": 600,
        "last_visit_date": "2025-01-01"
      }
    ]
  }
}

```

{% hint style="warning" %}
**If you wish to delete a specific property value inside an object, you should use PARTIAL\_UPDATE. Please refer to use case #3.**
{% endhint %}

#### **#6 - Override an array of objects - PARTIAL\_UPDATE** using the `@UpdateValueObject` directive

```graphql
# Schema extract

type UserProfile {
   compartment_id : String!
   user_account_id : String
   segmentations: [Segmentation]
}

type Segmentation @UpdateValueObject {
   type: String
   label: String
}
```

```json
//Existing profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "segmentations": [
    { "type": "segRFM", "label": "seg1" },
    { "type": "segRFM", "label": "seg2" }
  ]
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "segmentations": [ // contains the new value of the object
    { "type": "segOther", "label": "seg3" },
    { "type": "segOther", "label": "seg4" }
  ]
}

//New profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "segmentations": [ //full array of objects was replaced
    { "type": "segOther", "label": "seg3" },
    { "type": "segOther", "label": "seg4" }
  ]
}

```

#### **#7 - Override an object - PARTIAL\_UPDATE** using the `@UpdateValueObject` directive

```graphql
# Schema extract

type UserProfile {
   compartment_id : String!
   user_account_id : String
   geolocation: Geolocation
}

type Geolocation @UpdateValueObject {
   address: String
   city: String
   postal_code : String
}
```

```json
//Existing profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "geolocation": 
    { "address": "1 first avenue", 
      "city": "new york",
      "postal_code" :"0101" 
    }
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "geolocation": 
    { "address": "1 first avenue", 
      "city": "new york"
    }
}

//New profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "geolocation": 
    { "address": "1 first avenue", 
      "city": "new york"
    }
}

```

#### **#8 - Update properties inside the UserProfile - PARTIAL\_UPDATE with no directive**

```graphql
# Schema extract

type UserProfile {
   compartment_id : String!
   user_account_id : String
   first_name: String
   last_name : String
}
```

```json
//Existing profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "first_name" : "john"
  "last_name" : "doe"
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "first_name" : null
  "last_name" : "smith"
}

//New profile

{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "last_name" : "smith"
}

```

#### **#9 - Update a property inside an object - PARTIAL\_UPDATE with no directive**

```graphql
# Schema extract

type UserProfile {
   compartment_id : String!
   user_account_id : String
   geo_location: GeoLocation
}

type GeoLocation {
   address: String
   postal_code: String
   city: String
   country: String
}
```

<pre class="language-json"><code class="lang-json"><strong>//Existing profile
</strong>
{
  "compartment_id": "&#x3C;COMPARTMENT_ID>",
  "user_account_id": "&#x3C;USER_ACCOUNT_ID>",
  "geo_location": {
    "address": "1 main street",
    "city": "paris",
    "postal_code" : "0001",
    "country" : "France"
  }
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "&#x3C;COMPARTMENT_ID>",
  "user_account_id": "&#x3C;USER_ACCOUNT_ID>",
 "geo_location": {
    "address": null,
    "city": "New york",
  }
}

//New profile

{
  "compartment_id": "&#x3C;COMPARTMENT_ID>",
  "user_account_id": "&#x3C;USER_ACCOUNT_ID>",
  "geo_location": {
    "city": "new york",
    "postal_code" : "0001",
    "country" : "France"
  }
}

</code></pre>

#### **#10 - Override an object - PARTIAL\_UPDATE with no directive**

```graphql
# Schema extract

type UserProfile {
   compartment_id : String!
   user_account_id : String
   geo_location: GeoLocation
}

type GeoLocation {
   address: String
   postal_code: String
   city: String
   country: String
}
```

<pre class="language-json"><code class="lang-json"><strong>//Existing profile
</strong>
{
  "compartment_id": "&#x3C;COMPARTMENT_ID>",
  "user_account_id": "&#x3C;USER_ACCOUNT_ID>",
  "geo_location": {
    "address": "1 main street",
    "city": "paris",
    "postal_code" : "0001",
    "country" : "France"
  }
}

//Profile in update payload with update_strategy == PARTIAL_UPDATE
{
  "compartment_id": "&#x3C;COMPARTMENT_ID>",
  "user_account_id": "&#x3C;USER_ACCOUNT_ID>",
 "geo_location": {
    "address": "52 fifth avenue",
    "city": "New York City",
    "postal_code" : "12345",
    "country" : "USA"
  }
}

//New profile

{
  "compartment_id": "&#x3C;COMPARTMENT_ID>",
  "user_account_id": "&#x3C;USER_ACCOUNT_ID>",
  "geo_location": {
    "address": "52 fifth avenue",
    "city": "New York City",
    "postal_code" : "12345",
    "country" : "USA"
  }
}

</code></pre>

#### Constraints and limitations

**Schema related constraints :**&#x20;

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

* If a property is in the payload of the request but not declared in the schema, the whole request will fail. However, if a property is already present in the profile but not declared in the schema, it will not be overwritten by a partial update or delete. In fact it will not be possible to update such property unless using `FORCE_REPLACE`
* If the types of the properties in the payload of the request do not respect the schema, the whole request will fail.&#x20;

{% hint style="info" %}

* It is possible to define a hierarchy of inner objects while using `@UpdateStrategyKey` at each level
* However, `@UpdateStrategyKey` should only be set to one property inside a given object
  {% endhint %}

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

################################

#This is not allowed
type LoyaltyCard {
  card_id:String @UpdateStrategyKey
  benefits: Int @UpdateStrategyKey
  last_visit_date: Date  
}

```

**Limitations :**

* If a property in the schema has a directive such as `@Property(path: “[parent].property”)` (referencing \[parent] in path) :  this property cannot be updated with the partial update&#x20;
* Updatable properties cannot be computed values such as : computed field, ML function, results of function.
* `@UpdateValueObject` cannot be used with `@UpdateStrategyKey` in the same object

### FORCE\_REPLACE

When importing user profiles using `UPSERT`, if you wish to update existing profiles by completely overwriting the existing profiles you should use the `FORCE_REPLACE` value of the `update_strategy` property: the user profile will be completely replaced by the object passed in the `user_profile` property.

```bash
# Stored profile:
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      {
        "benefits": 200,
        "card_id": "abc",
        "last_visit_date": "2024-01-01"
      }
    ]
  }
}


# New profile in request payload
curl -X POST \
  https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
  -H 'Authorization: <API_TOKEN>' \
  -H 'Content-Type: application/x-ndjson' \
  -d '{ 
        "operation": "UPSERT",
        "compartment_id": "<COMPARTMENT_ID>", 
        "user_account_id": "<USER_ACCOUNT_ID>",
        "update_strategy": "FORCE_REPLACE",
        "user_profile": {
          "compartment_id": "<COMPARTMENT_ID>",
          "user_account_id": "<USER_ACCOUNT_ID>",
          "loyalty": {
            "cards": [
              {
                "benefits": 500,
                "card_id": "xyz",
                "last_visit_date": "2025-01-01"
              }
            ]
          }
        }
      }'

# New saved profile:
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      {
        "benefits": 500,
        "card_id": "xyz",
        "last_visit_date": "2025-01-01"
      }
    ]
  }
}
```

## Legacy parameters

| property       | type               | description                                                                                                                                                                                                                                                                                                                           |
| -------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| force\_replace | Boolean (Optional) | <p>Mandatory when the operation is <code>UPSERT</code>.<br><br>If true, then the User Profile will be completely replaced by the object passed in the <code>user\_profile</code> field.<br>If false, the object passed in the <code>user\_profile</code> field will be merged with the existing User Profile of the UserPoint.</p>    |
| merge\_objects | Boolean (Optional) | <p>Only considered if <code>force\_replace</code> is false.</p><p><br>Manage the comportement between two objects with a same property. </p><p><br>If false (default value), the new object overrides the existing one. </p><p>If true the new object is merged in deep to the existing one (see <a href="#example">example</a>).</p> |

More details on `merge_objects` behavior :

```bash
# Stored profile:
{
  "my_property_1": "value1",
  "my_property_2": "value1",
  "my_array_property": ["value1"]
  "my_array_object_property": [
    {
      "my_sub_array_object_property_1": "value1",
      "my_sub_array_object_property_2": "value1"
    }
  ],
  "my_object_property": {
    "my_sub_object_property_1": "value1",
    "my_sub_object_property_2": "value1"
  }    
}


# New profile in request payload
curl -X POST \
  https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
  -H 'Authorization: <API_TOKEN>' \
  -H 'Content-Type: application/x-ndjson' \
  -d '{ 
        "operation": "UPSERT",
        "compartment_id": "<COMPARTMENT_ID>", 
        "user_account_id": "<USER_ACCOUNT_ID>",
        "force_replace": false,
        "merge_objects": true,
        "user_profile": {
          "my_property_2": "value2",
          "my_property_3": "value3",
          "my_array_property": ["value2"]
          "my_array_object_property": [
            {
              "my_sub_array_object_property_2": "value2"
              "my_sub_array_object_property_3": "value3"
            }
          ],
          "my_object_property": {
            "my_sub_object_property_2": "value2"
            "my_sub_object_property_3": "value3"
          }    
        }
      }'

# New saved profile:
{
  "my_property_1": "value1",
  "my_property_2": "value2", # override scalar property
  "my_property_3": "value3",
  "my_array_property": ["value1","value2"] # merge arrays
  "my_array_object_property": [ # merge arrays
    {
      "my_sub_array_object_property_1": "value1"
      "my_sub_array_object_property_2": "value1"
    },
    {
      "my_sub_array_object_property_2": "value2"
      "my_sub_array_object_property_3": "value3"
    }
  ],
  "my_object_property": { # merge objects
    "my_sub_object_property_1": "value1"
    "my_sub_object_property_2": "value2" # override scalar property within object
    "my_sub_object_property_3": "value3"
  }    
}
```
