docs: document JSON properties (#13099)

This commit is contained in:
Shahed Nasser
2025-07-31 12:22:32 +03:00
committed by GitHub
parent 1c1e1c6aa2
commit 54a74b0215
14 changed files with 1072 additions and 17 deletions
@@ -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.