docs: document JSON properties (#13099)
This commit is contained in:
@@ -20,6 +20,12 @@ const generatedgeneratedAdminSidebarSidebar = {
|
||||
"path": "http-compression",
|
||||
"loaded": true
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"title": "Manage Metadata",
|
||||
"path": "manage-metadata",
|
||||
"loaded": true
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"title": "Select Fields and Relations",
|
||||
|
||||
@@ -26,6 +26,12 @@ const generatedgeneratedStoreSidebarSidebar = {
|
||||
"path": "http-compression",
|
||||
"loaded": true
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"title": "Manage Metadata",
|
||||
"path": "manage-metadata",
|
||||
"loaded": true
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"title": "Select Fields and Relations",
|
||||
|
||||
@@ -483,6 +483,226 @@ x-no-compression: false
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
## Manage Metadata
|
||||
|
||||
Many data models in Medusa, such as products and carts, have a `metadata` field that allows you to store custom information in key-value pairs.
|
||||
|
||||
When setting or updating the `metadata` field using the relevant API routes, Medusa will merge the new metadata with the existing metadata.
|
||||
|
||||
<Note>
|
||||
|
||||
The instructions in this section apply to any [JSON property in a data model](!docs!/learn/fundamentals/data-models/json-properties).
|
||||
|
||||
</Note>
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownLayout addYSpacing>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
### Accepted Values in Metadata
|
||||
|
||||
The `metadata` is an object of key-value pairs, where the keys are strings and the values can be one of the following types:
|
||||
|
||||
- String
|
||||
- An empty string deletes the property from the metadata.
|
||||
- Number
|
||||
- Boolean
|
||||
- Date
|
||||
- Object
|
||||
- Arrays of any of the above types
|
||||
|
||||
The `metadata` is not validated, so you can store any custom data in it.
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
<DividedMarkdownCode>
|
||||
|
||||
```ts title="Metadata Example"
|
||||
{
|
||||
"metadata": {
|
||||
"category": "electronics",
|
||||
"views": 1500,
|
||||
"is_featured": true,
|
||||
"tags": ["new", "sale"],
|
||||
"details": {
|
||||
"warranty": "2 years",
|
||||
"origin": "USA"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</DividedMarkdownCode>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownLayout addYSpacing>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
### Add or Update New Property in Metadata
|
||||
|
||||
To add or update a property in the `metadata`, pass the property in the request body as a key-value pair. This won't affect existing properties in the metadata.
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
<DividedMarkdownCode>
|
||||
|
||||
<CodeTabs group="request-with-result">
|
||||
|
||||
<CodeTab label="JS SDK" value="js-sdk">
|
||||
|
||||
```js title="Add new metadata property"
|
||||
sdk.admin.product.update("prod_123", {
|
||||
metadata: {
|
||||
new_property: "value"
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
<CodeTab label="Result" value="result">
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "prod_123",
|
||||
"metadata": {
|
||||
"new_property": "value",
|
||||
"old_property": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
</DividedMarkdownCode>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownLayout addYSpacing>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
### Update Nested Objects in Metadata
|
||||
|
||||
When updating a nested object in the `metadata`, you must pass the entire object in the request body.
|
||||
|
||||
Medusa doesn't merge nested objects, so if you pass a partial object, the existing properties in the nested object will be removed.
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
<DividedMarkdownCode>
|
||||
|
||||
<CodeTabs group="request-with-result">
|
||||
|
||||
<CodeTab label="JS SDK" value="js-sdk">
|
||||
|
||||
```js title="Update nested object in metadata"
|
||||
sdk.admin.product.update("prod_123", {
|
||||
metadata: {
|
||||
nested_object: {
|
||||
property1: "value1",
|
||||
property2: "value2"
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
<CodeTab label="Result" value="result">
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "prod_123",
|
||||
"metadata": {
|
||||
"nested_object": {
|
||||
"property1": "value1",
|
||||
"property2": "value2"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
</DividedMarkdownCode>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownLayout addYSpacing>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
### Remove Property from Metadata
|
||||
|
||||
To remove a property from the `metadata`, pass the property in the request body with an empty string value. This will remove the property from the `metadata` without affecting other properties.
|
||||
|
||||
<Feedback
|
||||
event="survey_api-ref"
|
||||
extraData={{
|
||||
area: "store",
|
||||
section: "metadata"
|
||||
}}
|
||||
pathName="/api/store"
|
||||
question="Was this section helpful?"
|
||||
vertical={true}
|
||||
/>
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
<DividedMarkdownCode>
|
||||
|
||||
<CodeTabs group="request-with-result">
|
||||
|
||||
<CodeTab label="JS SDK" value="js-sdk">
|
||||
|
||||
```js title="Remove metadata property"
|
||||
sdk.admin.product.update("prod_123", {
|
||||
metadata: {
|
||||
property_to_remove: ""
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
<CodeTab label="Result" value="result">
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "prod_123",
|
||||
"metadata": {
|
||||
"other_property": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
</DividedMarkdownCode>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
</SectionContainer>
|
||||
|
||||
<SectionContainer noTopPadding={true}>
|
||||
|
||||
<DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
## Select Fields and Relations
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
@@ -441,6 +441,253 @@ x-no-compression: false
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
## Manage Metadata
|
||||
|
||||
Many data models in Medusa, such as products and carts, have a `metadata` field that allows you to store custom information in key-value pairs.
|
||||
|
||||
When setting or updating the `metadata` field using the relevant API routes, Medusa will merge the new metadata with the existing metadata.
|
||||
|
||||
<Note>
|
||||
|
||||
The instructions in this section apply to any [JSON property in a data model](!docs!/learn/fundamentals/data-models/json-properties).
|
||||
|
||||
</Note>
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownLayout addYSpacing>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
### Accepted Values in Metadata
|
||||
|
||||
The `metadata` is an object of key-value pairs, where the keys are strings and the values can be one of the following types:
|
||||
|
||||
- String
|
||||
- An empty string deletes the property from the metadata.
|
||||
- Number
|
||||
- Boolean
|
||||
- Date
|
||||
- Object
|
||||
- Arrays of any of the above types
|
||||
|
||||
The `metadata` is not validated, so you can store any custom data in it.
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
<DividedMarkdownCode>
|
||||
|
||||
```ts title="Metadata Example"
|
||||
{
|
||||
"metadata": {
|
||||
"category": "electronics",
|
||||
"views": 1500,
|
||||
"is_featured": true,
|
||||
"tags": ["new", "sale"],
|
||||
"details": {
|
||||
"warranty": "2 years",
|
||||
"origin": "USA"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</DividedMarkdownCode>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownLayout addYSpacing>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
### Add or Update New Property in Metadata
|
||||
|
||||
To add or update a property in the `metadata`, pass the property in the request body as a key-value pair. This won't affect existing properties in the metadata.
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
<DividedMarkdownCode>
|
||||
|
||||
<CodeTabs group="request-with-result">
|
||||
|
||||
<CodeTab label="JS SDK" value="js-sdk">
|
||||
|
||||
```js title="Add new metadata property"
|
||||
sdk.store.cart.updateLineItem(
|
||||
"cart_123",
|
||||
"li_123",
|
||||
{
|
||||
metadata: {
|
||||
new_property: "value"
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
<CodeTab label="Result" value="result">
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "cart_123",
|
||||
"items": [
|
||||
{
|
||||
"id": "li_123",
|
||||
"metadata": {
|
||||
"new_property": "value",
|
||||
"old_property": "value"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
</DividedMarkdownCode>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownLayout addYSpacing>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
### Update Nested Objects in Metadata
|
||||
|
||||
When updating a nested object in the `metadata`, you must pass the entire object in the request body.
|
||||
|
||||
Medusa doesn't merge nested objects, so if you pass a partial object, the existing properties in the nested object will be removed.
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
<DividedMarkdownCode>
|
||||
|
||||
<CodeTabs group="request-with-result">
|
||||
|
||||
<CodeTab label="JS SDK" value="js-sdk">
|
||||
|
||||
```js title="Update nested object in metadata"
|
||||
sdk.store.cart.updateLineItem(
|
||||
"cart_123",
|
||||
"li_123",
|
||||
{
|
||||
metadata: {
|
||||
nested_object: {
|
||||
property1: "value1",
|
||||
property2: "value2"
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
<CodeTab label="Result" value="result">
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "cart_123",
|
||||
"items": [
|
||||
{
|
||||
"id": "li_123",
|
||||
"metadata": {
|
||||
"nested_object": {
|
||||
"property1": "value1",
|
||||
"property2": "value2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
</DividedMarkdownCode>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownLayout addYSpacing>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
### Remove Property from Metadata
|
||||
|
||||
To remove a property from the `metadata`, pass the property in the request body with an empty string value. This will remove the property from the `metadata` without affecting other properties.
|
||||
|
||||
<Feedback
|
||||
event="survey_api-ref"
|
||||
extraData={{
|
||||
area: "store",
|
||||
section: "metadata"
|
||||
}}
|
||||
pathName="/api/store"
|
||||
question="Was this section helpful?"
|
||||
vertical={true}
|
||||
/>
|
||||
|
||||
</DividedMarkdownContent>
|
||||
|
||||
<DividedMarkdownCode>
|
||||
|
||||
<CodeTabs group="request-with-result">
|
||||
|
||||
<CodeTab label="JS SDK" value="js-sdk">
|
||||
|
||||
```js title="Remove metadata property"
|
||||
sdk.store.cart.updateLineItem(
|
||||
"cart_123",
|
||||
"li_123",
|
||||
{
|
||||
metadata: {
|
||||
property_to_remove: ""
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
<CodeTab label="Result" value="result">
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "cart_123",
|
||||
"items": [
|
||||
{
|
||||
"id": "li_123",
|
||||
"metadata": {
|
||||
"other_property": "value"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
</DividedMarkdownCode>
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
</SectionContainer>
|
||||
|
||||
<SectionContainer noTopPadding={true}>
|
||||
|
||||
<DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
|
||||
## Select Fields and Relations
|
||||
|
||||
</DividedMarkdownContent>
|
||||
@@ -1167,6 +1414,10 @@ This sorts the products by their `created_at` field in the descending order.
|
||||
|
||||
</DividedMarkdownLayout>
|
||||
|
||||
</SectionContainer>
|
||||
|
||||
<SectionContainer noTopPadding={true}>
|
||||
|
||||
<DividedMarkdownLayout>
|
||||
|
||||
<DividedMarkdownContent>
|
||||
@@ -1184,10 +1435,10 @@ Refer to [this guide](!docs!/learn/customization/extend-features/extend-create-p
|
||||
<Feedback
|
||||
event="survey_api-ref"
|
||||
extraData={{
|
||||
area: "admin",
|
||||
area: "store",
|
||||
section: "workflows"
|
||||
}}
|
||||
pathName="/api/admin"
|
||||
pathName="/api/store"
|
||||
question="Was this section helpful?"
|
||||
vertical={true}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} JSON Properties in Data Models`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll learn how to use and manage [JSON properties](../properties/page.mdx#json) in data models.
|
||||
|
||||
## What is a JSON Property?
|
||||
|
||||
A JSON property in a data model is a flexible object that can contain various types of values.
|
||||
|
||||
For example, you can create a `Brand` data model with a `metadata` JSON property to store additional information about the brand:
|
||||
|
||||
```ts highlights={[["6"]]}
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const Brand = model.define("brand", {
|
||||
id: model.id().primaryKey(),
|
||||
name: model.text(),
|
||||
metadata: model.json(),
|
||||
})
|
||||
```
|
||||
|
||||
### Accepted Values in JSON Property
|
||||
|
||||
JSON properties are made up of key-value pairs. The keys are strings, and the values can be one of the following types:
|
||||
|
||||
- **Strings**: Text values.
|
||||
- Empty strings remove the property from the JSON object. Learn more in the [Remove a Property from the JSON Property](#remove-a-property-from-the-json-property) section.
|
||||
- **Numbers**: Numeric values.
|
||||
- **Booleans**: `true` or `false` values.
|
||||
- **Nested Objects**: Objects within objects.
|
||||
- **Arrays**: Lists of values of any of the above types.
|
||||
|
||||
For example, a `metadata` JSON property can look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"category": "electronics",
|
||||
"views": 1500,
|
||||
"is_featured": true,
|
||||
"tags": ["new", "sale"],
|
||||
"details": {
|
||||
"warranty": "2 years",
|
||||
"origin": "USA"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### What are JSON Properties Useful For?
|
||||
|
||||
JSON properties allow you to store flexible and dynamic data structures that can evolve over time without requiring changes to the database schema.
|
||||
|
||||
Most data models in Medusa's Commerce Modules have a `metadata` property that is a JSON object. `metadata` allows you to store custom information that is not part of the core data model.
|
||||
|
||||
Some examples of data to store in JSON properties:
|
||||
|
||||
- Custom gift message for line items in an order.
|
||||
- Product's ID in a third-party system.
|
||||
- Brand's category or tags.
|
||||
|
||||
### What are JSON Properties Not Useful For?
|
||||
|
||||
JSON properties are not suitable for structured data that requires strict validation or relationships with other data models.
|
||||
|
||||
For example, if you want to re-use brands across different products, it's better to create a `Brand` data model and [define a link](../../module-links/page.mdx) to the `Product` data model instead of storing brand information in the product's `metadata` JSON property.
|
||||
|
||||
---
|
||||
|
||||
## How to Manage JSON Properties?
|
||||
|
||||
### How Medusa Updates JSON Properties
|
||||
|
||||
Consider a Brand Module with a `Brand` data model as shown [in the previous section](#what-are-json-properties). The [module's service](../../modules/page.mdx#2-create-service) will extend `MedusaService`, which generates methods like [updateBrands](!resources!/service-factory-reference/methods/update) to update a brand.
|
||||
|
||||
When you pass a JSON property in the `updateBrands` method, Medusa will merge the provided JSON object with the existing one in the database. So, only the properties you pass will be updated, and the rest will remain unchanged.
|
||||
|
||||
The following sections show examples of how to add, update, and remove properties in a JSON property.
|
||||
|
||||
<Note title="Prerequisite" forceMultiline>
|
||||
|
||||
The following examples assume you have a `brandModuleService` that is resolved from the [Medusa container](../../medusa-container/page.mdx). For example:
|
||||
|
||||
```ts
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
```
|
||||
|
||||
</Note>
|
||||
|
||||
### Add a Property to the JSON Property
|
||||
|
||||
Continuing with the Brand example, to add a `category` property to the `metadata` property, pass the new property in the `update` or `create` methods:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
category: "electronics",
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated to include the new `category` property:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "electronics"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you want to add another `is_featured` property later, you can do so by passing it in the update method again without affecting the existing properties:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
is_featured: true,
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated to include both `category` and `is_featured` properties:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "electronics",
|
||||
"is_featured": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Update an Existing Property in the JSON Property
|
||||
|
||||
To update an existing property in the JSON property, pass the updated value in the `update` method.
|
||||
|
||||
Continuing with the Brand example, to update the `category` property in the `metadata`:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
category: "home appliances",
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated to reflect the new `category` value, and existing properties will remain unchanged:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "home appliances",
|
||||
"is_featured": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Caveat: Updating Nested Objects
|
||||
|
||||
If you want to update a nested object within the JSON property, you need to provide the entire nested object in the update method.
|
||||
|
||||
For example, consider that you have a `details` object within the `metadata`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "electronics",
|
||||
"details": {
|
||||
"warranty": "1 year",
|
||||
"origin": "China"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To update the `warranty` property within the `details` object, you need to provide the entire `details` object in the update method:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
details: {
|
||||
warranty: "2 years",
|
||||
origin: "China"
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated with the new `warranty` value:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "electronics",
|
||||
"details": {
|
||||
"warranty": "2 years",
|
||||
"origin": "China"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Remove a Property from the JSON Property
|
||||
|
||||
To remove a property from the JSON property, you can pass an empty string as the value of the property in the update method.
|
||||
|
||||
For example, to remove the `is_featured` property from the `metadata`:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
is_featured: "",
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated to remove the `is_featured` property:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "home appliances"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -220,7 +220,7 @@ export default Post
|
||||
|
||||
### json
|
||||
|
||||
The `json` method defines a property whose value is a stringified JSON object.
|
||||
The `json` method defines a property whose value is stored as a stringified JSON object in the database.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -237,6 +237,8 @@ const Post = model.define("post", {
|
||||
export default Post
|
||||
```
|
||||
|
||||
Learn more in the [JSON Properties](../json-properties/page.mdx) chapter.
|
||||
|
||||
### array
|
||||
|
||||
The `array` method defines an array of strings property.
|
||||
|
||||
@@ -115,7 +115,7 @@ export const generatedEditDates = {
|
||||
"app/learn/configurations/ts-aliases/page.mdx": "2025-07-23T15:32:18.008Z",
|
||||
"app/learn/production/worker-mode/page.mdx": "2025-07-18T15:19:45.352Z",
|
||||
"app/learn/fundamentals/module-links/read-only/page.mdx": "2025-07-25T07:58:54.327Z",
|
||||
"app/learn/fundamentals/data-models/properties/page.mdx": "2025-07-25T13:40:28.866Z",
|
||||
"app/learn/fundamentals/data-models/properties/page.mdx": "2025-07-31T08:22:20.431Z",
|
||||
"app/learn/fundamentals/framework/page.mdx": "2025-06-26T14:26:22.120Z",
|
||||
"app/learn/fundamentals/api-routes/retrieve-custom-links/page.mdx": "2025-07-14T10:24:32.582Z",
|
||||
"app/learn/fundamentals/workflows/errors/page.mdx": "2025-04-25T14:26:25.000Z",
|
||||
@@ -126,5 +126,6 @@ export const generatedEditDates = {
|
||||
"app/learn/installation/docker/page.mdx": "2025-07-23T15:34:18.530Z",
|
||||
"app/learn/fundamentals/generated-types/page.mdx": "2025-07-25T13:17:35.319Z",
|
||||
"app/learn/introduction/from-v1-to-v2/page.mdx": "2025-07-30T08:13:48.592Z",
|
||||
"app/learn/debugging-and-testing/debug-workflows/page.mdx": "2025-07-30T13:45:14.117Z"
|
||||
"app/learn/debugging-and-testing/debug-workflows/page.mdx": "2025-07-30T13:45:14.117Z",
|
||||
"app/learn/fundamentals/data-models/json-properties/page.mdx": "2025-07-31T08:38:55.014Z"
|
||||
}
|
||||
@@ -513,6 +513,16 @@ export const generatedSidebars = [
|
||||
"chapterTitle": "3.5.2. Properties",
|
||||
"number": "3.5.2."
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"type": "link",
|
||||
"path": "/learn/fundamentals/data-models/json-properties",
|
||||
"title": "JSON Properties",
|
||||
"children": [],
|
||||
"chapterTitle": "3.5.3. JSON Properties",
|
||||
"number": "3.5.3."
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
@@ -520,8 +530,8 @@ export const generatedSidebars = [
|
||||
"path": "/learn/fundamentals/data-models/relationships",
|
||||
"title": "Relationships",
|
||||
"children": [],
|
||||
"chapterTitle": "3.5.3. Relationships",
|
||||
"number": "3.5.3."
|
||||
"chapterTitle": "3.5.4. Relationships",
|
||||
"number": "3.5.4."
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -530,8 +540,8 @@ export const generatedSidebars = [
|
||||
"path": "/learn/fundamentals/data-models/manage-relationships",
|
||||
"title": "Manage Relationships",
|
||||
"children": [],
|
||||
"chapterTitle": "3.5.4. Manage Relationships",
|
||||
"number": "3.5.4."
|
||||
"chapterTitle": "3.5.5. Manage Relationships",
|
||||
"number": "3.5.5."
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -540,8 +550,8 @@ export const generatedSidebars = [
|
||||
"path": "/learn/fundamentals/data-models/index",
|
||||
"title": "Define Index",
|
||||
"children": [],
|
||||
"chapterTitle": "3.5.5. Define Index",
|
||||
"number": "3.5.5."
|
||||
"chapterTitle": "3.5.6. Define Index",
|
||||
"number": "3.5.6."
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -550,8 +560,8 @@ export const generatedSidebars = [
|
||||
"path": "/learn/fundamentals/data-models/check-constraints",
|
||||
"title": "Check Constraints",
|
||||
"children": [],
|
||||
"chapterTitle": "3.5.6. Check Constraints",
|
||||
"number": "3.5.6."
|
||||
"chapterTitle": "3.5.7. Check Constraints",
|
||||
"number": "3.5.7."
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -560,8 +570,8 @@ export const generatedSidebars = [
|
||||
"path": "/learn/fundamentals/data-models/write-migration",
|
||||
"title": "Migrations",
|
||||
"children": [],
|
||||
"chapterTitle": "3.5.7. Migrations",
|
||||
"number": "3.5.7."
|
||||
"chapterTitle": "3.5.8. Migrations",
|
||||
"number": "3.5.8."
|
||||
}
|
||||
],
|
||||
"chapterTitle": "3.5. Data Models",
|
||||
|
||||
@@ -9604,6 +9604,237 @@ class BlogModuleService extends MedusaService({ Post }) {
|
||||
```
|
||||
|
||||
|
||||
# JSON Properties in Data Models
|
||||
|
||||
In this chapter, you'll learn how to use and manage [JSON properties](https://docs.medusajs.com/learn/fundamentals/data-models/properties#json/index.html.md) in data models.
|
||||
|
||||
## What is a JSON Property?
|
||||
|
||||
A JSON property in a data model is a flexible object that can contain various types of values.
|
||||
|
||||
For example, you can create a `Brand` data model with a `metadata` JSON property to store additional information about the brand:
|
||||
|
||||
```ts highlights={[["6"]]}
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const Brand = model.define("brand", {
|
||||
id: model.id().primaryKey(),
|
||||
name: model.text(),
|
||||
metadata: model.json(),
|
||||
})
|
||||
```
|
||||
|
||||
### Accepted Values in JSON Property
|
||||
|
||||
JSON properties are made up of key-value pairs. The keys are strings, and the values can be one of the following types:
|
||||
|
||||
- **Strings**: Text values.
|
||||
- Empty strings remove the property from the JSON object. Learn more in the [Remove a Property from the JSON Property](#remove-a-property-from-the-json-property) section.
|
||||
- **Numbers**: Numeric values.
|
||||
- **Booleans**: `true` or `false` values.
|
||||
- **Nested Objects**: Objects within objects.
|
||||
- **Arrays**: Lists of values of any of the above types.
|
||||
|
||||
For example, a `metadata` JSON property can look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"category": "electronics",
|
||||
"views": 1500,
|
||||
"is_featured": true,
|
||||
"tags": ["new", "sale"],
|
||||
"details": {
|
||||
"warranty": "2 years",
|
||||
"origin": "USA"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### What are JSON Properties Useful For?
|
||||
|
||||
JSON properties allow you to store flexible and dynamic data structures that can evolve over time without requiring changes to the database schema.
|
||||
|
||||
Most data models in Medusa's Commerce Modules have a `metadata` property that is a JSON object. `metadata` allows you to store custom information that is not part of the core data model.
|
||||
|
||||
Some examples of data to store in JSON properties:
|
||||
|
||||
- Custom gift message for line items in an order.
|
||||
- Product's ID in a third-party system.
|
||||
- Brand's category or tags.
|
||||
|
||||
### What are JSON Properties Not Useful For?
|
||||
|
||||
JSON properties are not suitable for structured data that requires strict validation or relationships with other data models.
|
||||
|
||||
For example, if you want to re-use brands across different products, it's better to create a `Brand` data model and [define a link](https://docs.medusajs.com/learn/fundamentals/module-links/index.html.md) to the `Product` data model instead of storing brand information in the product's `metadata` JSON property.
|
||||
|
||||
***
|
||||
|
||||
## How to Manage JSON Properties?
|
||||
|
||||
### How Medusa Updates JSON Properties
|
||||
|
||||
Consider a Brand Module with a `Brand` data model as shown [in the previous section](#what-are-json-properties). The [module's service](https://docs.medusajs.com/learn/fundamentals/modules#2-create-service/index.html.md) will extend `MedusaService`, which generates methods like [updateBrands](https://docs.medusajs.com/resources/service-factory-reference/methods/update/index.html.md) to update a brand.
|
||||
|
||||
When you pass a JSON property in the `updateBrands` method, Medusa will merge the provided JSON object with the existing one in the database. So, only the properties you pass will be updated, and the rest will remain unchanged.
|
||||
|
||||
The following sections show examples of how to add, update, and remove properties in a JSON property.
|
||||
|
||||
The following examples assume you have a `brandModuleService` that is resolved from the [Medusa container](https://docs.medusajs.com/learn/fundamentals/medusa-container/index.html.md). For example:
|
||||
|
||||
```ts
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
```
|
||||
|
||||
### Add a Property to the JSON Property
|
||||
|
||||
Continuing with the Brand example, to add a `category` property to the `metadata` property, pass the new property in the `update` or `create` methods:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
category: "electronics",
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated to include the new `category` property:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "electronics"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you want to add another `is_featured` property later, you can do so by passing it in the update method again without affecting the existing properties:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
is_featured: true,
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated to include both `category` and `is_featured` properties:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "electronics",
|
||||
"is_featured": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Update an Existing Property in the JSON Property
|
||||
|
||||
To update an existing property in the JSON property, pass the updated value in the `update` method.
|
||||
|
||||
Continuing with the Brand example, to update the `category` property in the `metadata`:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
category: "home appliances",
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated to reflect the new `category` value, and existing properties will remain unchanged:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "home appliances",
|
||||
"is_featured": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Caveat: Updating Nested Objects
|
||||
|
||||
If you want to update a nested object within the JSON property, you need to provide the entire nested object in the update method.
|
||||
|
||||
For example, consider that you have a `details` object within the `metadata`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "electronics",
|
||||
"details": {
|
||||
"warranty": "1 year",
|
||||
"origin": "China"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To update the `warranty` property within the `details` object, you need to provide the entire `details` object in the update method:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
details: {
|
||||
warranty: "2 years",
|
||||
origin: "China"
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated with the new `warranty` value:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "electronics",
|
||||
"details": {
|
||||
"warranty": "2 years",
|
||||
"origin": "China"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Remove a Property from the JSON Property
|
||||
|
||||
To remove a property from the JSON property, you can pass an empty string as the value of the property in the update method.
|
||||
|
||||
For example, to remove the `is_featured` property from the `metadata`:
|
||||
|
||||
```ts
|
||||
const brand = await brandModuleService.updateBrands({
|
||||
id: "brand_123",
|
||||
metadata: {
|
||||
is_featured: "",
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The brand record will now have the `metadata` property updated to remove the `is_featured` property:
|
||||
|
||||
```json title="Result"
|
||||
{
|
||||
"id": "brand_123",
|
||||
"metadata": {
|
||||
"category": "home appliances"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# Manage Relationships
|
||||
|
||||
In this chapter, you'll learn how to manage relationships between data models when creating, updating, or retrieving records using the module's main service.
|
||||
@@ -10114,7 +10345,7 @@ export default Post
|
||||
|
||||
### json
|
||||
|
||||
The `json` method defines a property whose value is a stringified JSON object.
|
||||
The `json` method defines a property whose value is stored as a stringified JSON object in the database.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -10129,6 +10360,8 @@ const Post = model.define("post", {
|
||||
export default Post
|
||||
```
|
||||
|
||||
Learn more in the [JSON Properties](https://docs.medusajs.com/learn/fundamentals/data-models/json-properties/index.html.md) chapter.
|
||||
|
||||
### array
|
||||
|
||||
The `array` method defines an array of strings property.
|
||||
@@ -80661,6 +80894,40 @@ Learn more about accepted filters in [this documentation](https://docs.medusajs.
|
||||
|
||||
The method returns an array of objects of updated records.
|
||||
|
||||
***
|
||||
|
||||
## Update a JSON Property
|
||||
|
||||
```ts
|
||||
const post = await postModuleService.updatePosts({
|
||||
id: "123",
|
||||
name: "My Post",
|
||||
metadata: {
|
||||
category: "news",
|
||||
tags: ["update", "json"],
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
When you have a JSON property in your data model, you can update it by adding, updating, or removing properties within that JSON object. Medusa will merge the properties you pass in the `update` method with the existing JSON object.
|
||||
|
||||
### Remove a Property from the JSON Property
|
||||
|
||||
```ts
|
||||
const post = await postModuleService.updatePosts({
|
||||
id: "123",
|
||||
metadata: {
|
||||
is_featured: "",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
To remove a property from the JSON object, you can set its value to an empty string.
|
||||
|
||||
### Learn More about Updating JSON Properties
|
||||
|
||||
Refer to the [JSON Properties](https://docs.medusajs.com/docs/learn/fundamentals/data-models/json-properties/index.html.md) documentation to learn more about how JSON properties work in Medusa and how to update them.
|
||||
|
||||
|
||||
# Service Factory Reference
|
||||
|
||||
|
||||
@@ -274,6 +274,11 @@ export const sidebars = [
|
||||
path: "/learn/fundamentals/data-models/properties",
|
||||
title: "Properties",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: "/learn/fundamentals/data-models/json-properties",
|
||||
title: "JSON Properties",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: "/learn/fundamentals/data-models/relationships",
|
||||
|
||||
@@ -135,3 +135,37 @@ Learn more about accepted filters in [this documentation](../../tips/filtering/p
|
||||
### Returns
|
||||
|
||||
The method returns an array of objects of updated records.
|
||||
|
||||
---
|
||||
|
||||
## Update a JSON Property
|
||||
|
||||
```ts
|
||||
const post = await postModuleService.updatePosts({
|
||||
id: "123",
|
||||
name: "My Post",
|
||||
metadata: {
|
||||
category: "news",
|
||||
tags: ["update", "json"],
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
When you have a JSON property in your data model, you can update it by adding, updating, or removing properties within that JSON object. Medusa will merge the properties you pass in the `update` method with the existing JSON object.
|
||||
|
||||
### Remove a Property from the JSON Property
|
||||
|
||||
```ts
|
||||
const post = await postModuleService.updatePosts({
|
||||
id: "123",
|
||||
metadata: {
|
||||
is_featured: "",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
To remove a property from the JSON object, you can set its value to an empty string.
|
||||
|
||||
### Learn More about Updating JSON Properties
|
||||
|
||||
Refer to the [JSON Properties](!docs!/learn/fundamentals/data-models/json-properties) documentation to learn more about how JSON properties work in Medusa and how to update them.
|
||||
|
||||
@@ -131,7 +131,7 @@ export const generatedEditDates = {
|
||||
"app/service-factory-reference/methods/restore/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/service-factory-reference/methods/retrieve/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/service-factory-reference/methods/soft-delete/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/service-factory-reference/methods/update/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/service-factory-reference/methods/update/page.mdx": "2025-07-31T08:24:03.685Z",
|
||||
"app/service-factory-reference/tips/filtering/page.mdx": "2025-04-23T14:38:29.068Z",
|
||||
"app/service-factory-reference/page.mdx": "2024-07-26T14:40:56+00:00",
|
||||
"app/storefront-development/cart/context/page.mdx": "2025-03-27T14:47:14.258Z",
|
||||
|
||||
@@ -6102,6 +6102,14 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
|
||||
"path": "https://docs.medusajs.com/resources/how-to-tutorials/tutorials/gift-message",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"type": "ref",
|
||||
"title": "Generate Invoices",
|
||||
"path": "https://docs.medusajs.com/resources/how-to-tutorials/tutorials/invoice-generator",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
|
||||
@@ -819,6 +819,14 @@ const generatedgeneratedToolsSidebarSidebar = {
|
||||
"path": "https://docs.medusajs.com/resources/how-to-tutorials/tutorials/first-purchase-discounts",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"type": "ref",
|
||||
"title": "Generate Invoices",
|
||||
"path": "https://docs.medusajs.com/resources/how-to-tutorials/tutorials/invoice-generator",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
|
||||
Reference in New Issue
Block a user