docs: improve database operations docs + added data model repository reference (#12273)

* some changes

* docs: improve database operations docs + add data model repository reference

* regenerate
This commit is contained in:
Shahed Nasser authored and GitHub committed 2025-04-23 19:22:50 +03:00
1 parent 876a14eb98
commit 54bae210b8
21 files changed
+20651 -17089

No files matched your search

@@ -1,4 +1,4 @@
import { CodeTabs, CodeTab } from "docs-ui"
import { CodeTabs, CodeTab, TypeList } from "docs-ui"
export const metadata = {
title: `${pageNumber} Perform Database Operations in a Service`,
@@ -78,7 +78,18 @@ Refer to [MikroORM's reference](https://mikro-orm.io/api/knex/class/EntityManage
---
## Execute Operations in Transactions
## Perform Database Operations
There are two ways to perform database operations in transactional methods:
1. Using the [data model repositories](#perform-database-operations-with-data-model-repositories) in your module.
2. Using the [transactional entity manager](#perform-database-operations-with-the-transactional-entity-manager) injected into the method's shared context.
For both approaches, you must wrap the method performing the database operations in a transaction.
### Wrap Database Operations in Transactions
When performing database operations without using the [Service Factory](../service-factory/page.mdx), you must wrap the method performing the database operations in a transaction.
To wrap database operations in a transaction, you create two methods:
@@ -92,9 +103,7 @@ For example:
export const opHighlights = [
["11", "InjectTransactionManager", "A decorator that injects the a transactional entity manager into the `sharedContext` parameter."],
["17", "MedusaContext", "A decorator to use Medusa's shared context."],
["20", "nativeUpdate", "Update a record."],
["31", "execute", "Retrieve the updated record."],
["38", "InjectManager", "A decorator that injects a forked entity manager into the context."],
["24", "InjectManager", "A decorator that injects a forked entity manager into the context."],
]
```ts highlights={opHighlights}
@@ -106,6 +115,273 @@ import {
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
class BlogModuleService {
// ...
@InjectTransactionManager()
protected async update_(
input: {
id: string,
name: string
},
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const transactionManager = sharedContext?.transactionManager
// TODO: update the record
}
@InjectManager()
async update(
input: {
id: string,
name: string
},
@MedusaContext() sharedContext?: Context<EntityManager>
) {
return await this.update_(input, sharedContext)
}
}
```
The `BlogModuleService` has two methods:
- A protected `update_` that performs the database operations inside a transaction.
- A public `update` that executes the transactional protected method.
You can then perform in the transactional method the database operations either using the [data model repository](#perform-database-operations-with-data-model-repositories) or the [transactional entity manager](#perform-database-operations-with-the-transactional-entity-manager).
#### Why Wrap a Transactional Method
The variables in the transactional method (such as `update_`) hold values that are uncommitted to the database. They're only committed once the method finishes execution.
So, if in your method you perform database operations, then use their result to perform other actions, such as connecting to a third-party service, you'll be working with uncommitted data.
By placing only the database operations in a method that has the `InjectTransactionManager` and using it in a wrapper method, the wrapper method receives the committed result of the transactional method.
<Note title="Optimization Tip">
This is also useful if you perform heavy data normalization outside of the database operations. In that case, you don't hold the transaction for a longer time than needed.
</Note>
For example, the `update` method may call other methods than `update_` to perform other actions:
```ts
// other imports...
import {
InjectManager,
InjectTransactionManager,
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
class BlogModuleService {
// ...
@InjectTransactionManager()
protected async update_(
// ...
): Promise<any> {
// ...
}
@InjectManager()
async update(
input: {
id: string,
name: string
},
@MedusaContext() sharedContext?: Context<EntityManager>
) {
const newData = await this.update_(input, sharedContext)
// example method that sends data to another system
await this.sendNewDataToSystem(newData)
return newData
}
}
```
In this case, only the `update_` method is wrapped in a transaction. The returned value `newData` holds the committed result, which can be used for other operations, such as passed to a `sendNewDataToSystem` method.
#### Using Methods in Transactional Methods
If your protected transactional method uses other methods that accept a Medusa context, pass the shared context to those methods.
For example:
export const anotherMethodHighlights = [
["26", "sharedContext", "Pass the context to the other transactional method."]
]
```ts highlights={anotherMethodHighlights}
// other imports...
import {
InjectTransactionManager,
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
class BlogModuleService {
// ...
@InjectTransactionManager()
protected async anotherMethod(
@MedusaContext() sharedContext?: Context<EntityManager>
) {
// ...
}
@InjectTransactionManager()
protected async update_(
input: {
id: string,
name: string
},
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
this.anotherMethod(sharedContext)
}
}
```
You use the `anotherMethod` transactional method in the `update_` transactional method, so you pass it the shared context.
The `anotherMethod` now runs in the same transaction as the `update_` method.
### Perform Database Operations with Data Model Repositories
For every data model in your module, Medusa generates a data model repository that has methods to perform database operations.
For example, if your module has a `Post` model, it has a `postRepository` in the container.
The data model repository is a wrapper around the [entity manager](https://mikro-orm.io/api/knex/class/EntityManager) that provides a higher-level API for performing database operations.
<Note>
To use the low-level entity manager, use the [transactional entity manager](#perform-database-operations-with-the-transactional-entity-manager) instead.
</Note>
#### Resolve Data Model Repository
When the Medusa application injects a data model repository into a module's container, it formats the registration name by:
- Taking the data model's name that's passed as the first parameter of `model.define`
- Lower-casing the first character
- Suffixing the result with `Repository`.
For example:
- `Post` model: `postRepository`
- `My_Custom` model: `my_CustomRepository`
So, to resolve a data model repository from a module's container, pass the expected registration name of the repository in the first parameter of the module's constructor (the container).
For example:
<CodeTabs group="service-type">
<CodeTab label="Extending Service Factory" value="service-factory">
export const serviceFactoryRepoHighlights = [
["20", "postRepository", "Resolve the data model repository of the `Post` model."],
]
```ts highlights={serviceFactoryRepoHighlights}
import { MedusaService } from "@medusajs/framework/utils"
import { InferTypeOf, DAL } from "@medusajs/framework/types"
import Post from "./models/post"
type Post = InferTypeOf<typeof Post>
type InjectedDependencies = {
postRepository: DAL.RepositoryService<Post>
}
class BlogModuleService extends MedusaService({
Post,
}){
protected postRepository_: DAL.RepositoryService<Post>
constructor({
postRepository
}: InjectedDependencies) {
super(...arguments)
this.postRepository_ = postRepository
}
}
export default BlogModuleService
```
</CodeTab>
<CodeTab label="Without Service Factory" value="no-service-factory">
export const noServiceFactoryRepoHighlights = [
["17", "postRepository", "Resolve the data model repository of the `Post` model."],
]
```ts highlights={noServiceFactoryRepoHighlights}
import { InferTypeOf, DAL } from "@medusajs/framework/types"
import Post from "./models/post"
type Post = InferTypeOf<typeof Post>
type InjectedDependencies = {
postRepository: DAL.RepositoryService<Post>
}
class BlogModuleService {
protected postRepository_: DAL.RepositoryService<Post>
constructor({
postRepository
}: InjectedDependencies) {
super(...arguments)
this.postRepository_ = postRepository
}
}
export default BlogModuleService
```
</CodeTab>
</CodeTabs>
You can then use the data model repository in your service to perform database operations.
#### Data Model Repository Methods
A data model repository has methods that allows you to create, update, and delete records, among other operations.
To learn about the methods available in a data model repository, refer to the [Data Model Repository](!resources!/data-model-repository-reference) reference.
### Perform Database Operations with the Transactional Entity Manager
Your transactional method can use the transactional entity manager injected into the method's shared context to perform database operations. It's an instance of the [MikroORM EntityManager](https://mikro-orm.io/api/knex/class/EntityManager) class.
<Note>
To use an easier higher-level API focused on each data model, use the [data model repository](#perform-database-operations-with-data-model-repositories) instead.
</Note>
For example:
export const transactionalEntityManagerHighlights = [
["19", "transactionManager", "Use the transactional entity manager injected\ninto the `sharedContext` parameter."],
["20", "nativeUpdate", "Perform a native update operation."],
["31", "execute", "Perform a native query operation."],
]
```ts highlights={transactionalEntityManagerHighlights}
import {
InjectManager,
InjectTransactionManager,
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
class BlogModuleService {
// ...
@InjectTransactionManager()
@@ -148,119 +424,15 @@ class BlogModuleService {
}
```
The `BlogModuleService` has two methods:
The `update_` method uses the transactional entity manager injected into the `sharedContext.transactionManager` property to perform the database operations.
- A protected `update_` that performs the database operations inside a transaction.
- A public `update` that executes the transactional protected method.
The shared context's `transactionManager` property holds the transactional entity manager (injected by `InjectTransactionManager`) that you use to perform database operations.
<Note>
Refer to [MikroORM's reference](https://mikro-orm.io/api/knex/class/EntityManager) for a full list of the entity manager's methods.
</Note>
### Why Wrap a Transactional Method
The variables in the transactional method (for example, `update_`) hold values that are uncommitted to the database. They're only committed once the method finishes execution.
So, if in your method you perform database operations, then use their result to perform other actions, such as connecting to a third-party service, you'll be working with uncommitted data.
By placing only the database operations in a method that has the `InjectTransactionManager` and using it in a wrapper method, the wrapper method receives the committed result of the transactional method.
<Note title="Optimization Tip">
This is also useful if you perform heavy data normalization outside of the database operations. In that case, you don't hold the transaction for a longer time than needed.
</Note>
For example, the `update` method could be changed to the following:
```ts
// other imports...
import {
InjectManager,
InjectTransactionManager,
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
class BlogModuleService {
// ...
@InjectTransactionManager()
protected async update_(
// ...
): Promise<any> {
// ...
}
@InjectManager()
async update(
input: {
id: string,
name: string
},
@MedusaContext() sharedContext?: Context<EntityManager>
) {
const newData = await this.update_(input, sharedContext)
// example method that sends data to another system
await this.sendNewDataToSystem(newData)
return newData
}
}
```
In this case, only the `update_` method is wrapped in a transaction. The returned value `newData` holds the committed result, which can be used for other operations, such as passed to a `sendNewDataToSystem` method.
### Using Methods in Transactional Methods
If your transactional method uses other methods that accept a Medusa context, pass the shared context to those methods.
For example:
```ts
// other imports...
import {
InjectTransactionManager,
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
class BlogModuleService {
// ...
@InjectTransactionManager()
protected async anotherMethod(
@MedusaContext() sharedContext?: Context<EntityManager>
) {
// ...
}
@InjectTransactionManager()
protected async update_(
input: {
id: string,
name: string
},
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
this.anotherMethod(sharedContext)
}
}
```
You use the `anotherMethod` transactional method in the `update_` transactional method, so you pass it the shared context.
The `anotherMethod` now runs in the same transaction as the `update_` method.
Find all available methods in the [MikroORM EntityManager](https://mikro-orm.io/api/knex/class/EntityManager) reference.
---
## Configure Transactions
## Configure Transactions with the Base Repository
To configure the transaction, such as its [isolation level](https://www.postgresql.org/docs/current/transaction-iso.html), use the `baseRepository` dependency registered in your module's container.
To configure the transaction, such as its [isolation level](https://www.postgresql.org/docs/current/transaction-iso.html), use the `baseRepository` class registered in your module's container.
The `baseRepository` is an instance of a repository class that provides methods to create transactions, run database operations, and more.
@@ -271,7 +443,11 @@ For example, resolve the `baseRepository` in your service's constructor:
<CodeTabs group="service-type">
<CodeTab label="Extending Service Factory" value="service-factory">
```ts highlights={[["14"]]}
export const baseRepoHighlights = [
["16", "baseRepository", "Resolve the base repository."],
]
```ts highlights={baseRepoHighlights}
import { MedusaService } from "@medusajs/framework/utils"
import Post from "./models/post"
import { DAL } from "@medusajs/framework/types"
@@ -293,10 +469,15 @@ class BlogModuleService extends MedusaService({
export default BlogModuleService
```
</CodeTab>
<CodeTab label="Without Service Factory" value="no-service-factory">
```ts highlights={[["10"]]}
export const noServiceFactoryBaseRepoHighlights = [
["11", "baseRepository", "Resolve the base repository."],
]
```ts highlights={noServiceFactoryBaseRepoHighlights}
import { DAL } from "@medusajs/framework/types"
type InjectedDependencies = {
@@ -317,7 +498,7 @@ export default BlogModuleService
</CodeTab>
</CodeTabs>
Then, add the following method that uses it:
Then, use it in the service's transactional methods:
export const repoHighlights = [
["20", "transaction", "Wrap the function parameter in a transaction."]
@@ -399,7 +580,7 @@ The second parameter of the `baseRepository_.transaction` method is an object of
1. `transaction`: Set the transactional entity manager passed to the function. You must provide this option as explained in the previous section.
```ts highlights={[["16"]]}
```ts highlights={[["24"]]}
// other imports...
import { EntityManager } from "@mikro-orm/knex"
import {
@@ -407,7 +588,6 @@ import {
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
class BlogModuleService {
// ...
@@ -438,7 +618,7 @@ class BlogModuleService {
- `repeatable read`
- `serializable`
```ts highlights={[["19"]]}
```ts highlights={[["25"]]}
// other imports...
import {
InjectTransactionManager,
@@ -473,7 +653,7 @@ class BlogModuleService {
3. `enableNestedTransactions`: (default: `false`) whether to allow using nested transactions.
- If `transaction` is provided and this is disabled, the manager in `transaction` is re-used.
```ts highlights={[["16"]]}
```ts highlights={[["24"]]}
// other imports...
import {
InjectTransactionManager,
+1 -1
View File
@@ -68,7 +68,7 @@ export const generatedEditDates = {
"app/learn/fundamentals/module-links/directions/page.mdx": "2025-03-17T12:52:06.161Z",
"app/learn/fundamentals/module-links/page.mdx": "2025-04-17T08:50:17.036Z",
"app/learn/fundamentals/module-links/query/page.mdx": "2025-04-18T11:13:02.240Z",
"app/learn/fundamentals/modules/db-operations/page.mdx": "2025-03-21T09:21:46.901Z",
"app/learn/fundamentals/modules/db-operations/page.mdx": "2025-04-23T14:24:37.910Z",
"app/learn/fundamentals/modules/multiple-services/page.mdx": "2025-03-18T15:11:44.632Z",
"app/learn/fundamentals/modules/page.mdx": "2025-03-18T07:51:09.049Z",
"app/learn/debugging-and-testing/instrumentation/page.mdx": "2025-02-24T08:12:53.132Z",
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,85 @@
---
sidebar_label: "create"
---
import { TypeList } from "docs-ui"
export const metadata = {
title: `create Method - Data Model Repository Reference`,
}
# {metadata.title}
The `create` method of a data model repository creates one or more records of the data model.
<Note>
This reference assumes you've already resolved the data model repository, as explained in the [Data Model Repository Reference](../../page.mdx) documentation.
</Note>
## `create` Parameters
<TypeList
types={[
{
type: "`array`",
name: "data",
description: "An array of objects to create. The shape of the objects is the same as the shape of the data model.",
required: true,
}
]}
sectionTitle="create Parameters"
/>
---
## Create Records
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const posts = await this.postRepository_.create([
{
title: "My Post",
content: "This is a post",
author_id: "01JSGRGQ8S61SR0Y7VCRV8FH66",
}
])
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The `create` method accepts an array of objects, each representing a record to create. The shape of the objects is the same as the shape of the data model.
### Returns
The method returns an array of the created records.
@@ -0,0 +1,138 @@
---
sidebar_label: "delete"
---
import { TypeList } from "docs-ui"
export const metadata = {
title: `delete Method - Data Model Repository Reference`,
}
# {metadata.title}
The `delete` method of a data model repository deletes one or more records of the data model.
<Note>
This reference assumes you've already resolved the data model repository, as explained in the [Data Model Repository Reference](../../page.mdx) documentation.
</Note>
## `delete` Parameters
<TypeList
types={[
{
type: "`object`",
name: "filters",
description: "The filters to select the records to delete. The keys are the property names of the data model, and the values are the values to filter by.",
required: true,
}
]}
sectionTitle="delete Parameters"
/>
---
## Delete Record by ID
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const deletedIds = await this.postRepository_.delete({
id
})
return deletedIds
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The `delete` method accepts an object of filters to select the records to delete.
In the example above, you pass an object with the `id` property to delete a record by its ID.
### Returns
The method returns an array of strings, each representing the ID of a deleted record.
---
## Delete Records by Filters
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const deletedIds = await this.postRepository_.delete({
title: "My Post"
})
return deletedIds
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
Since the `delete` method accepts an object of filters, you can pass any property of the data model as a filter.
In the example above, you pass an object with the `title` property to delete all records with that title.
<Note>
Find examples of different filters in the [Filter Records](../../tips/filtering/page.mdx) documentation.
</Note>
### Returns
The method returns an array of strings, each representing the ID of a deleted record.
@@ -0,0 +1,460 @@
---
sidebar_label: "find"
---
import { TypeList } from "docs-ui"
export const metadata = {
title: `find Method - Data Model Repository Reference`,
}
# {metadata.title}
The `find` method of a data model repository retrieves a list of records.
<Note>
This reference assumes you've already resolved the data model repository, as explained in the [Data Model Repository Reference](../../page.mdx) documentation.
</Note>
## `find` Parameters
<TypeList
types={[
{
type: "`object`",
name: "data",
description: "Options to filter and configure the query to retrieve the records.",
required: false,
children: [
{
type: "`object`",
name: "where",
description: "Filters to apply to the query. The keys are the property names of the data model, and the values are the values to filter by.",
required: false,
},
{
type: "`object`",
name: "options",
description: "Options to configure the query.",
required: false,
children: [
{
type: "`string[]`",
name: "populate",
description: "An array of relation names to retrieve.",
required: false,
},
{
type: "`string[]`",
name: "fields",
description: "An array of property names to retrieve.",
required: false,
},
{
type: "`number`",
name: "limit",
description: "The number of records to retrieve.",
required: false,
defaultValue: "`15`",
},
{
type: "`number`",
name: "offset",
description: "The number of records to skip before the retrieved records.",
required: false,
defaultValue: "`0`",
},
{
type: "`object`",
name: "orderBy",
description: "An object whose keys are the property names of the data model, and values are the sorting order.",
required: false,
},
{
type: "`string | string[]`",
name: "groupBy",
description: "Group the records by one or more properties.",
required: false,
},
{
type: "`select-in` \\| `joined`",
name: "strategy",
description: "The strategy to use to retrieve the records. Learn more in the [MikroORM documentation](https://mikro-orm.io/docs/loading-strategies). If you don't specify a strategy and you specify the `limit` or `offset` options, the default strategy is `select-in`. Otherwise, the default strategy is `joined`.",
required: false,
}
]
}
]
}
]}
sectionTitle="find Parameters"
openedLevel={1}
/>
---
## Retrieve List of Records
To retrieve a list of records matching a set of filters, use the `find` method of the data model repository:
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const posts = await this.postRepository_.find()
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Returns
By default, the method returns an array of the first `15` records of the data model.
---
## Filter Records
You can filter the retrieved records by passing filters as a first parameter of the `find` method:
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const posts = await this.postRepository_.find({
where: {
id,
},
})
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The first object parameter is an object that has a `where` property used to apply filters. `where`'s value is an object whose keys are the property names of the data model, and values are the values to filter by.
In the example above, you filter the retrieved posts by their `id` property.
<Note>
Refer to the [Filtering](../../tips/filtering/page.mdx) reference for more information on how to filter records.
</Note>
### Returns
The method returns an array of the first `15` records matching the filters.
---
## Retrieve Relations
<Note>
This applies to relations between data models of the same module. To retrieve linked records of different modules, use [Query](!docs!/learn/fundamentals/module-links/query).
</Note>
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const posts = await this.postRepository_.find({
where: {
id
},
options: {
populate: ["author"]
}
})
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The first object parameter of `find` accepts an `option` property, whose value is an object of retrieval options.
It accepts a `populate` property, whose value is an array of relation names to retrieve.
In the example above, you retrieve the `author` relation of the posts.
### Returns
The method returns an array of the first `15` records. Each record will have the specified relations populated:
```json title="Example"
[
{
"id": "1",
"author": {
"id": "1",
"name": "John Doe",
// ...
},
// ...
}
]
```
---
## Select Properties
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const posts = await this.postRepository_.find({
where: {
id
},
options: {
fields: ["title"]
}
})
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
By default, retrieved records have all their properties. The first object parameter of `find` accepts in its `options` property a `fields` property, whose value is an array of property names to retrieve.
In the example above, you retrieve only the `title` property of the posts.
### Returns
The method returns an array of the first `15` records. Each record will have only the specified properties:
```json title="Example"
[
{
"id": "1",
"title": "My first post"
}
]
```
---
## Paginate Relations
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const posts = await this.postRepository_.find({
where: {
id
},
options: {
limit: 10,
offset: 10,
}
})
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
By default, the `find` method retrieves the first `15` records.
To change pagination configurations, you can pass to the first object parameter the `options` property, whose value is an object that accepts the following properties for pagination:
- `limit`: a number indicating how many records to retrieve. By default, it's `15`.
- `offset`: a number indicating how many records to skip before the retrieved records. By default, it's `0`.
In the example above, you retrieve `10` records, skipping the first `10` records.
### Returns
The method returns an array of records. The number of records is less than or equal to `limit`'s value.
---
## Sort Records
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const posts = await this.postRepository_.find({
where: {
id
},
options: {
orderBy: {
title: "ASC"
}
}
})
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
To sort records by one or more properties, the first object parameter of `find` accepts in its `options` property an `orderBy` property. Its value is an object whose keys are the property names of the data model, and values are the sorting order.
The sorting order can be one of the following:
- `ASC` to sort by this property in the ascending order.
- `DESC` to sort by this property in the descending order.
### Returns
The method returns an array of the first `15` records sorted by the specified properties.
@@ -0,0 +1,495 @@
---
sidebar_label: "findAndCount"
---
import { TypeList } from "docs-ui"
export const metadata = {
title: `findAndCount Method - Data Model Repository Reference`,
}
# {metadata.title}
The `findAndCount` method of a data model repository retrieves a list of records and the total count of records that match the query.
<Note>
This reference assumes you've already resolved the data model repository, as explained in the [Data Model Repository Reference](../../page.mdx) documentation.
</Note>
## `findAndCount` Parameters
<TypeList
types={[
{
type: "`object`",
name: "data",
description: "Options to filter and configure the query to retrieve the records.",
required: false,
children: [
{
type: "`object`",
name: "where",
description: "Filters to apply to the query. The keys are the property names of the data model, and the values are the values to filter by.",
required: false,
},
{
type: "`object`",
name: "options",
description: "Options to configure the query.",
required: false,
children: [
{
type: "`string[]`",
name: "populate",
description: "An array of relation names to retrieve.",
required: false,
},
{
type: "`string[]`",
name: "fields",
description: "An array of property names to retrieve.",
required: false,
},
{
type: "`number`",
name: "limit",
description: "The number of records to retrieve.",
required: false,
defaultValue: "`15`",
},
{
type: "`number`",
name: "offset",
description: "The number of records to skip before the retrieved records.",
required: false,
defaultValue: "`0`",
},
{
type: "`object`",
name: "orderBy",
description: "An object whose keys are the property names of the data model, and values are the sorting order.",
required: false,
},
{
type: "`string | string[]`",
name: "groupBy",
description: "Group the records by one or more properties.",
required: false,
},
{
type: "`select-in` \\| `joined`",
name: "strategy",
description: "The strategy to use to retrieve the records. Learn more in the [MikroORM documentation](https://mikro-orm.io/docs/loading-strategies). If you don't specify a strategy and you specify the `limit` or `offset` options, the default strategy is `select-in`. Otherwise, the default strategy is `joined`.",
required: false,
}
]
}
]
}
]}
sectionTitle="findAndCount Parameters"
openedLevel={1}
/>
---
## Retrieve List of Records
To retrieve a list of records matching a set of filters, use the `findAndCount` method of the data model repository:
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [posts, count] = await this.postRepository_.findAndCount()
return {
posts,
count
}
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Returns
The method returns a tuple of two elements:
- An array of the first `15` records of the data model.
- The total count of records that match the query.
---
## Filter Records
You can filter the retrieved records by passing filters as a first parameter of the `findAndCount` method:
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [posts, count] = await this.postRepository_.findAndCount({
where: {
id,
},
})
return {
posts,
count
}
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The first object parameter is an object that has a `where` property used to apply filters. `where`'s value is an object whose keys are the property names of the data model, and values are the values to filter by.
In the example above, you filter the retrieved posts by their `id` property.
<Note>
Refer to the [Filtering](../../tips/filtering/page.mdx) reference for more information on how to filter records.
</Note>
### Returns
The method returns a tuple of two elements:
- An array of the first `15` records matching the filters.
- The total count of records that match the query.
---
## Retrieve Relations
<Note>
This applies to relations between data models of the same module. To retrieve linked records of different modules, use [Query](!docs!/learn/fundamentals/module-links/query).
</Note>
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [posts, count] = await this.postRepository_.findAndCount({
where: {
id
},
options: {
populate: ["author"]
}
})
return {
posts,
count
}
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The first object parameter of `findAndCount` accepts an `options` property, whose value is an object of retrieval options.
It accepts a `populate` property, whose value is an array of relation names to retrieve.
In the example above, you retrieve the `author` relation of the posts.
### Returns
The method returns a tuple of two elements:
- An array of the first `15` records.
- The total count of records that match the query.
Each record in the array will have the specified relations populated:
```json title="Example"
[
{
"id": "1",
"author": {
"id": "1",
"name": "John Doe",
// ...
},
// ...
}
]
```
---
## Select Properties
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [posts, count] = await this.postRepository_.findAndCount({
where: {
id
},
options: {
fields: ["title"]
}
})
return {
posts,
count
}
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
By default, retrieved records have all their properties. The first object parameter of `findAndCount` accepts in its `options` property a `fields` property, whose value is an array of property names to retrieve.
In the example above, you retrieve only the `title` property of the posts.
### Returns
The method returns a tuple of two elements:
- An array of the first `15` records.
- The total count of records that match the query.
Each record in the array will have only the specified properties:
```json title="Example"
[
{
"id": "1",
"title": "My first post"
}
]
```
---
## Paginate Relations
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [posts, count] = await this.postRepository_.findAndCount({
where: {
id
},
options: {
limit: 10,
offset: 10,
}
})
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
By default, the `find` method retrieves the first `15` records.
To change pagination configurations, you can pass to the first object parameter the `options` property, whose value is an object that accepts the following properties for pagination:
- `limit`: a number indicating how many records to retrieve. By default, it's `15`.
- `offset`: a number indicating how many records to skip before the retrieved records. By default, it's `0`.
In the example above, you retrieve `10` records, skipping the first `10` records.
### Returns
The method returns an array of records. The number of records is less than or equal to `limit`'s value.
---
## Sort Records
```ts title="src/modules/blog/service.ts"
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [posts, count] = await this.postRepository_.findAndCount({
where: {
id
},
options: {
orderBy: {
title: "ASC"
}
}
})
return {
posts,
count
}
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
To sort records by one or more properties, the first object parameter of `findAndCount` accepts in its `options` property an `orderBy` property. Its value is an object whose keys are the property names of the data model, and values are the sorting order.
The sorting order can be one of the following:
- `ASC` to sort by this property in the ascending order.
- `DESC` to sort by this property in the descending order.
### Returns
The method returns a tuple of two elements:
- An array of the first `15` records.
- The total count of records that match the query.
@@ -0,0 +1,332 @@
---
sidebar_label: "restore"
---
import { TypeList } from "docs-ui"
export const metadata = {
title: `restore Method - Data Model Repository Reference`,
}
# {metadata.title}
The `restore` method of a data model repository restores one or more records of the data model that were previously soft-deleted.
This means that the `deleted_at` property of the records is set to `null`.
<Note>
This reference assumes you've already resolved the data model repository, as explained in the [Data Model Repository Reference](../../page.mdx) documentation.
</Note>
## `restore` Parameters
<TypeList
types={[
{
type: "`string` \\| `string[]` \\| `object`",
name: "filters",
description: "Can be either the ID of a record to restore, an array of records IDs to restore, or an object of filters to select the records to restore.",
required: true,
}
]}
sectionTitle="restore Parameters"
/>
---
## Restore Record by ID
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [
restoredPosts,
restoredEntities
] = await this.postRepository_.restore(id)
return restoredPosts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The `restore` method can accept the ID of a record to restore as a string.
### Returns
The method returns a tuple with two elements:
- The first element is an array of the restored records.
- The second element is an object whose keys are the names of restored data models, and values an array of restored record objects.
- This is useful if records from other data models were previously soft-deleted due to cascading soft-deletes, and are now restored.
For example:
```json title="Example"
[
[
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
],
{
"Post": [
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
]
}
]
```
---
## Restore Multiple Records By IDs
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
ids: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [
restoredPosts,
restoredEntities
] = await this.postRepository_.restore(ids)
return restoredPosts
}
@InjectManager()
async doSomething(
ids: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(ids, sharedContext)
}
}
```
### Parameters
The `restore` method can accept an array of record IDs to restore.
### Returns
The method returns a tuple with two elements:
- The first element is an array of the restored records.
- The second element is an object whose keys are the names of restored data models, and values an array of restored record objects.
- This is useful if records from other data models were previously soft-deleted due to cascading soft-deletes, and are now restored.
For example:
```json title="Example"
[
[
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
],
{
"Post": [
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
]
}
]
```
---
## Restore Records by Filters
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [
restoredPosts,
restoredEntities
] = await this.postRepository_.restore({
title: "My Post"
})
return restoredPosts
}
@InjectManager()
async doSomething(
ids: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(ids, sharedContext)
}
}
```
### Parameters
The `restore` method can accept an object of filters to select the records to restore.
In the example above, you pass an object with the `title` property to restore all records with that title.
<Note>
Find examples of different filters in the [Filter Records](../../tips/filtering/page.mdx) documentation.
</Note>
### Returns
The method returns a tuple with two elements:
- The first element is an array of the restored records.
- The second element is an object whose keys are the names of restored data models, and values an array of restored record objects.
- This is useful if records from other data models were previously soft-deleted due to cascading soft-deletes, and are now restored.
For example:
```json title="Example"
[
[
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
],
{
"Post": [
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
]
}
]
```
@@ -0,0 +1,334 @@
---
sidebar_label: "softDelete"
---
import { TypeList } from "docs-ui"
export const metadata = {
title: `softDelete Method - Data Model Repository Reference`,
}
# {metadata.title}
The `softDelete` method of a data model repository soft-deletes one or more records of the data model.
This means that the records are still available in the database, but they are marked as deleted by setting their `deleted_at` property to the deletion date.
You can later restore the records using the [restore](../restore/page.mdx) method.
<Note>
This reference assumes you've already resolved the data model repository, as explained in the [Data Model Repository Reference](../../page.mdx) documentation.
</Note>
## `softDelete` Parameters
<TypeList
types={[
{
type: "`string` \\| `string[]` \\| `object`",
name: "filters",
description: "Can be either the ID of a record to soft-delete, an array of records IDs to soft-delete, or an object of filters to select the records to soft-delete.",
required: true,
}
]}
sectionTitle="softDelete Parameters"
/>
---
## Soft-Delete Record by ID
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [
deletedPosts,
deletedEntities
] = await this.postRepository_.softDelete(id)
return deletedPosts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The `softDelete` method can accept the ID of a record to soft-delete as a string.
### Returns
The method returns a tuple with two elements:
- The first element is an array of the soft-deleted records.
- The second element is an object whose keys are the names of deleted data models, and values an array of deleted record objects.
- This is useful if records from other data models are soft-deleted due to cascading soft-deletes.
For example:
```json title="Example"
[
[
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
],
{
"Post": [
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
]
}
]
```
---
## Soft-Delete Multiple Records By IDs
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
ids: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [
deletedPosts,
deletedEntities
] = await this.postRepository_.softDelete(ids)
return deletedPosts
}
@InjectManager()
async doSomething(
ids: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(ids, sharedContext)
}
}
```
### Parameters
The `softDelete` method can accept an array of record IDs to soft-delete.
### Returns
The method returns a tuple with two elements:
- The first element is an array of the soft-deleted records.
- The second element is an object whose keys are the names of deleted data models, and values an array of deleted record objects.
- This is useful if records from other data models are soft-deleted due to cascading soft-deletes.
For example:
```json title="Example"
[
[
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
],
{
"Post": [
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
]
}
]
```
---
## Soft-Delete Records by Filters
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const [
deletedPosts,
deletedEntities
] = await this.postRepository_.softDelete({
title: "My Post"
})
return deletedPosts
}
@InjectManager()
async doSomething(
ids: string[],
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(ids, sharedContext)
}
}
```
### Parameters
The `softDelete` method can accept an object of filters to select the records to soft-delete.
In the example above, you pass an object with the `title` property to soft-delete all records with that title.
<Note>
Find examples of different filters in the [Filter Records](../../tips/filtering/page.mdx) documentation.
</Note>
### Returns
The method returns a tuple with two elements:
- The first element is an array of the soft-deleted records.
- The second element is an object whose keys are the names of deleted data models, and values an array of deleted record objects.
- This is useful if records from other data models are soft-deleted due to cascading soft-deletes.
For example:
```json title="Example"
[
[
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
],
{
"Post": [
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My first post",
"content": "This is my first post",
"metadata": null,
"product_id": null,
"product_ids": [
"prod_01JP4M5T5K55P2JN1F17EY7B2T"
],
"author_id": "01JSHAW6YZNKR65TJ242GCMD2S",
"author": "01JSHAW6YZNKR65TJ242GCMD2S",
"created_at": "2025-04-23T12:44:59.751Z",
"updated_at": "2025-04-23T12:44:59.751Z",
"deleted_at": "2025-04-23T12:45:08.750Z"
}
]
}
]
```
@@ -0,0 +1,113 @@
---
sidebar_label: "update"
---
import { TypeList } from "docs-ui"
export const metadata = {
title: `update Method - Data Model Repository Reference`,
}
# {metadata.title}
The `update` method of a data model repository updates one or more records of the data model.
<Note>
This reference assumes you've already resolved the data model repository, as explained in the [Data Model Repository Reference](../../page.mdx) documentation.
</Note>
## `update` Parameters
<TypeList
types={[
{
type: "`array`",
name: "data",
description: "An array of update details.",
required: true,
children: [
{
type: "`object`",
name: "entity",
description: "The entity to update. It must be the entire entity, which can be retrieved using the `find` method.",
required: true,
},
{
type: "`object`",
name: "update",
description: "The properties to update. The keys are the property names of the data model, and the values are the values to update.",
required: true,
}
]
}
]}
openedLevel={1}
sectionTitle="update Parameters"
/>
---
## Update Records
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const existingPost = await this.postRepository_.find({
where: {
id
}
})
const posts = await this.postRepository_.update([
{
entity: existingPost[0],
update: {
title: "My Post Updated"
}
}
])
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The `update` method accepts an array of objects, each representing a record to update.
Each object has two properties:
- `entity`: The entity or record to update. It must be the entire record, which can be retrieved using the [find](../find/page.mdx) or [findAndCount](../findAndCount/page.mdx) methods.
- `update`: The properties to update. The keys are the property names of the data model, and the values are the values to update.
In the example above, you retrieve the record to update using the `find` method. Then, you pass the entire record and the properties to update to the `update` method.
### Returns
The method returns an array of the updated records.
@@ -0,0 +1,92 @@
---
sidebar_label: "upsert"
---
import { TypeList } from "docs-ui"
export const metadata = {
title: `upsert Method - Data Model Repository Reference`,
}
# {metadata.title}
The `upsert` method of a data model repository creates or updates one or more records of the data model.
<Note>
This reference assumes you've already resolved the data model repository, as explained in the [Data Model Repository Reference](../../page.mdx) documentation.
</Note>
## `upsert` Parameters
<TypeList
types={[
{
type: "`array`",
name: "data",
description: "An array of records to create or update. If a record object has an `id` property, the method will try to update the record. Otherwise, the method will create a new record.",
required: true,
}
]}
sectionTitle="upsert Parameters"
/>
---
## Upsert Records
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const posts = await this.postRepository_.upsert([
{
id: "01JSHAW6Z7KW4X6E8MFPGNEKHC",
title: "My Old Post",
},
{
title: "My New Post",
}
])
return posts
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The `upsert` method accepts an array of objects, each representing a record to create or update.
If a record object has an `id` property, the method will try to update a record with that `id`. Otherwise, the method will create a new record.
If the `id` property is specified but no record with that `id` exists, the created record will have the specified `id`.
Each object has the same shape as the data model.
### Returns
The method returns an array of the created or updated records.
@@ -0,0 +1,149 @@
---
sidebar_label: "upsertWithReplace"
---
import { TypeList } from "docs-ui"
export const metadata = {
title: `upsertWithReplace Method - Data Model Repository Reference`,
}
# {metadata.title}
The `upsertWithReplace` method of a data model repository can do three things:
- Create a new record.
- Update an existing record.
- Delete a record related to the record being upserted. If a one-to-many or many-to-many relation is omitted in the new data of a record, the method will delete the related records if they belong to the record being upserted.
This method is useful when you're doing complex upserts with relations, or you want details of the operations performed. Otherwise, use the [upsert](../upsert/page.mdx) method.
<Note>
This reference assumes you've already resolved the data model repository, as explained in the [Data Model Repository Reference](../../page.mdx) documentation.
</Note>
## `upsertWithReplace` Parameters
<TypeList
types={[
{
type: "`array`",
name: "data",
description: "An array of records to create or update. If a record object has an `id` property, the method will try to update the record. Otherwise, the method will create a new record.",
required: true,
}
]}
sectionTitle="upsertWithReplace Parameters"
/>
---
## Upsert Records
```ts
import {
InjectTransactionManager,
MedusaContext,
MedusaService,
} from "@medusajs/framework/utils"
import { Context, InferTypeOf, DAL } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import Post from "./models/post"
class BlogModuleService extends MedusaService({
Post,
}){
// ...
@InjectTransactionManager()
protected async doSomething_(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
const {
entities,
performedActions
} = await this.postRepository_.upsertWithReplace([
{
id: "01JSHAW6Z7KW4X6E8MFPGNEKHC",
title: "My Old Post",
author_id: null
},
{
id: "123",
title: "My New Post",
}
])
return {
entities,
performedActions
}
}
@InjectManager()
async doSomething(
id: string,
@MedusaContext() sharedContext?: Context<EntityManager>
): Promise<any> {
return await this.doSomething_(id, sharedContext)
}
}
```
### Parameters
The `upsertWithReplace` method accepts an array of objects, each representing a record to create or update.
If a record object has an `id` property, the method will try to update a record with that `id`. Otherwise, the method will create a new record.
If the `id` property is specified but no record with that `id` exists, the created record will have the specified `id`.
Each object has the same shape as the data model.
### Returns
The method returns an object with two properties:
- `entities`: An array of the created or updated records.
- `performedActions`: An object with three properties:
- `created`: An object whose keys are the names of data models, and values are arrays of the records that were created.
- `updated`: An object whose keys are the names of data models, and values are arrays of the records that were updated.
- `deleted`: An object whose keys are the names of data models, and values are arrays of the records that were deleted.
For example:
```json title="Example"
{
"entities": [
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC",
"title": "My Old Post",
"author_id": null
},
{
"id": "123",
"title": "My New Post"
}
],
"performedActions": {
"created": {
"Post": [
{
"id": "123"
}
]
},
"updated": {
"Post": [
{
"id": "01JSHAW6Z7KW4X6E8MFPGNEKHC"
}
]
},
"deleted": {
}
}
}
```
@@ -0,0 +1,87 @@
import { ChildDocs } from "docs-ui"
export const metadata = {
title: `Data Model Repository Reference`,
}
# {metadata.title}
This section of the documentation provides a reference of the methods generated for data model repositories that are injected into a module's container.
<Note title="Tip">
Learn more about the data model repository in the [Database Operations](!docs!/learn/fundamentals/modules/db-operations) documentation.
</Note>
## When to Use the Data Model Repository?
If your module has data models, then you should always extend the [service factory](!docs!/learn/fundamentals/modules/service-factory). It generates basic data-mangement operations for your module's data models.
However, there are some cases where you might need to perform more complex database operations and need more control over the parameters you're passing.
In those cases, you can use the data model repository.
---
## Data Model Repository Registration Name
When the Medusa application injects a data model repository into a module's container, it formats the registration name by:
- Taking the data model's name that's passed as the first parameter of `model.define`
- Lower-casing the first character
- Suffixing the result with `Repository`.
For example:
- `Post` model: `postRepository`
- `My_Custom` model: `my_CustomRepository`
---
## Resolve Data Model Repository
To resolve a data model repository from a module's container, pass the data model's name in the first parameter of the module's constructor.
For example:
export const resolveRepoHighlights = [
["17", "postRepository", "Resolve the data model repository for the `Post` model."],
]
```ts highlights={resolveRepoHighlights}
import { MedusaService } from "@medusajs/framework/utils"
import { InferTypeOf, DAL } from "@medusajs/framework/types"
import Post from "./models/post"
type Post = InferTypeOf<typeof Post>
type InjectedDependencies = {
postRepository: DAL.RepositoryService<Post>
}
class BlogModuleService extends MedusaService({
Post,
}){
protected postRepository_: DAL.RepositoryService<Post>
constructor({
postRepository
}: InjectedDependencies) {
super(...arguments)
this.postRepository_ = postRepository
}
}
export default BlogModuleService
```
In this example, the `BlogModuleService` class resolves the `postRepository` from its container.
---
## Methods Reference
Learn how to use the data model repository's methods to perform database operations on the data model.
<ChildDocs showItems={["Methods"]} hideTitle />
@@ -0,0 +1,531 @@
---
sidebar_label: "Filtering"
---
import { Table } from "docs-ui"
export const metadata = {
title: `Filter Records - Data Model Repository Reference`,
}
# {metadata.title}
This reference provides examples to different filtering mechanisms and scenarios.
## Methods that Accept Filters
Some of the data model repository's methods allow you to pass filters, including:
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>
Method
</Table.HeaderCell>
<Table.HeaderCell>
Filter Parameter
</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>
[find](../../methods/find/page.mdx)
</Table.Cell>
<Table.Cell>
Accepts a `where` property in its first parameter to pass filters.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
[findAndCount](../../methods/findAndCount/page.mdx)
</Table.Cell>
<Table.Cell>
Accepts a `where` property in its first parameter to pass filters.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
[delete](../../methods/delete/page.mdx)
</Table.Cell>
<Table.Cell>
Accepts an object as a first parameter to pass filters.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
[softDelete](../../methods/softDelete/page.mdx)
</Table.Cell>
<Table.Cell>
Accepts an object as a first parameter to pass filters.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
[restore](../../methods/restore/page.mdx)
</Table.Cell>
<Table.Cell>
Accepts an object as a first parameter to pass filters.
</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
While the examples in this reference are based on the `find` method, the same filtering mechanisms apply to the other methods.
---
## Match Exact Value
```ts
const posts = await this.postRepository_.find({
where: {
title: "My Post"
},
})
```
If you pass a property with its value, only records whose properties exactly match the value are selected.
In the example above, only posts having the title `My Post` are retrieved.
---
## Doesn't Match Exact Value
```ts
const posts = await this.postRepository_.find({
where: {
title: {
$ne: "My Post",
}
},
})
```
To find records with a property that doesn't match a value, pass an object with a `$ne` property. Its value is the value that a record's property shouldn't match.
In the example above, only posts that don't have the title `My Post` are retrieved.
---
## Match Multiple Values
```ts
const posts = await this.postRepository_.find({
where: {
views: [
50,
100,
],
},
})
```
To find records with a property matching multiple values, pass an array of those values as the property's value in the filter.
In the example above, only posts having either `50` or `100` views are retrieved.
---
## Don't Match Multiple Values
```ts
const posts = await this.postRepository_.find({
where: {
title: {
$nin: ["My Post", "My Post 2"]
}
},
})
```
To find records with a property that doesn't match one or more values, pass an object with a `$nin` property. Its value is an array of multiple values that a record's property shouldn't match.
In the example above, only posts that don't have the title `My Post` are retrieved.
---
## Match Text Like Value
<Note>
This filter only applies to text-like properties, including `text`, `id`, and `enum` properties.
</Note>
```ts
const posts = await this.postRepository_.find({
where: {
title: {
$like: "My%"
}
},
})
```
To perform a `like` filter on a record's property, set the property's value to an object with a `$like` property. Its value is the string to use when applying the `like` filter.
The example above matches all posts whose title starts with `My`.
---
## Filter by Null or Not Null
To retrieve records with a property that is `null`, set the property's value to `null`.
For example:
```ts
const posts = await this.postRepository_.find({
where: {
published_at: null,
},
})
```
In the example above, only posts that have a `null` publish date are retrieved.
On the other hand, to retrieve records with a property that isn't `null`, set the property's value to an object with a `$ne` property.
For example:
```ts
const posts = await this.postRepository_.find({
where: {
published_at: {
$ne: null,
},
},
})
```
In the example above, only posts that have a publish date are retrieved.
---
## Apply Range Filters
<Note>
This filter only applies to the `number` and `dateTime` properties.
</Note>
```ts
const posts = await this.postRepository_.find({
where: {
published_at: {
$lt: new Date(),
},
},
})
```
To filter a record's property to be within a range, set the property's value to an object with any of the following properties:
1. `$lt`: The property's value must be less than the supplied value.
2. `$lte`: The property's value must be less than or equal to the supplied value.
3. `$gt`: The property's value must be greater than the supplied value.
4. `$gte`: The property's value must be greater than or equal the supplied value.
In the example above, only posts whose `published_at` property is before the current date and time are retrieved.
### Example: Retrieve Posts Published Today
```ts
const startToday = new Date()
startToday.setHours(0, 0, 0, 0)
const endToday = new Date()
endToday.setHours(23, 59, 59, 59)
const posts = await this.postRepository_.find({
where: {
published_at: {
$gte: startToday,
$lte: endToday,
},
},
})
```
The `dateTime` property also stores the time. So, when matching for an exact day, you must set a range filter to be between the beginning and end of the day.
In this example, you retrieve the current date twice: once to set its time to `00:00:00`, and another to set its time `23:59:59`. Then, you retrieve posts whose `published_at` property is between `00:00:00` and `23:59:59` of today.
### Example: Range Filter on Number Property
```ts
const posts = await this.postRepository_.find({
where: {
views: {
$gte: 50,
$lte: 100,
},
},
})
```
In the example above, only posts with `views` between `50` and `100` are retrieved.
---
## Apply Or Condition
```ts
const posts = await this.postRepository_.find({
where: {
$or: [
{
title: "My Post",
},
{
published_at: {
$lt: new Date(),
},
},
],
},
})
```
To use an `or` condition, pass to the filter object the `$or` property, whose value is an array of filters.
In the example above, posts whose title is `My Post` or their `published_at` date is less than the current date and time are retrieved.
---
## Apply And Condition
```ts
const posts = await this.postRepository_.find({
where: {
$and: [
{
title: "My Post",
},
{
published_at: {
$lt: new Date(),
},
},
],
},
})
```
To use an `and` condition, pass to the filter object the `$and` property, whose value is an array of filters.
In the example above, only posts whose title is `My Post` and their `published_at` date is less than the current date and time are retrieved.
---
## Complex Filters Example
```ts
const posts = await this.postRepository_.find({
where: {
$or: [
{
$and: [
{ views: { $gte: 50 } },
{
published_at: {
$gte: new Date(new Date().getFullYear(), 0, 1),
},
},
],
},
{
title: {
$like: "%Featured%",
},
},
],
},
})
```
In the example above, posts are retrieved if they meet either of the following conditions:
1. The post has at least `50` views and was published after the beginning of the current year.
2. The post's title contains the word `Featured`.
By combining `and` and `or` conditions, you can create complex filters to retrieve records that meet specific criteria.
---
## Supported Filter Operators List
The following operators are supported by the data model repository filtering mechanism:
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>
Operator
</Table.HeaderCell>
<Table.HeaderCell>
Description
</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row className="bg-medusa-bg-component">
<Table.Cell colSpan={2}>
Comparison Operators
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$eq`
</Table.Cell>
<Table.Cell>
Matches values that are equal to a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$ne`
</Table.Cell>
<Table.Cell>
Matches values that are not equal to a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$in`
</Table.Cell>
<Table.Cell>
Matches any of the values specified in an array.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$nin`
</Table.Cell>
<Table.Cell>
Matches none of the values specified in an array.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$like`
</Table.Cell>
<Table.Cell>
Matches values containing a specified substring.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$lt`
</Table.Cell>
<Table.Cell>
Matches values that are less than a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$lte`
</Table.Cell>
<Table.Cell>
Matches values that are less than or equal to a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$gt`
</Table.Cell>
<Table.Cell>
Matches values that are greater than a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$gte`
</Table.Cell>
<Table.Cell>
Matches values that are greater than or equal to a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$re`
</Table.Cell>
<Table.Cell>
Matches values that match a specified regular expression.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$ilike`
</Table.Cell>
<Table.Cell>
Matches values containing a specified substring, case-insensitive.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$fulltext`
</Table.Cell>
<Table.Cell>
Performs a full-text search on a text property.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$overlap`
</Table.Cell>
<Table.Cell>
Matches values that have overlapping elements with the specified array.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$contains`
</Table.Cell>
<Table.Cell>
Performs an `@> value` comparison. Learn more in the [PostgreSQL documentation](https://www.postgresql.org/docs/9.6/functions-array.html).
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$contained`
</Table.Cell>
<Table.Cell>
Performs an `value @>` comparison. Learn more in the [PostgreSQL documentation](https://www.postgresql.org/docs/9.6/functions-array.html).
</Table.Cell>
</Table.Row>
<Table.Row className="bg-medusa-bg-component">
<Table.Cell colSpan={2}>
Logical Operators
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$and`
</Table.Cell>
<Table.Cell>
Joins two or more conditions with a logical AND.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$or`
</Table.Cell>
<Table.Cell>
Joins two or more conditions with a logical OR.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$not`
</Table.Cell>
<Table.Cell>
Inverts the logic of a condition. For example, `$not: { $eq: value }` matches any value that is not equal to the specified value.
</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
@@ -2,6 +2,8 @@
sidebar_label: "Filtering"
---
import { Table } from "docs-ui"
export const metadata = {
title: `Filter Records - Service Factory Reference`,
}
@@ -273,4 +275,181 @@ In the example above, posts are retrieved if they meet either of the following c
1. The post has at least `50` views and was published after the beginning of the current year.
2. The post's title contains the word `Featured`.
By combining `and` and `or` conditions, you can create complex filters to retrieve records that meet specific criteria.
By combining `and` and `or` conditions, you can create complex filters to retrieve records that meet specific criteria.
---
## Supported Filter Operators List
The following operators are supported by the service factory filtering mechanism:
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>
Operator
</Table.HeaderCell>
<Table.HeaderCell>
Description
</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row className="bg-medusa-bg-component">
<Table.Cell colSpan={2}>
Comparison Operators
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$eq`
</Table.Cell>
<Table.Cell>
Matches values that are equal to a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$ne`
</Table.Cell>
<Table.Cell>
Matches values that are not equal to a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$in`
</Table.Cell>
<Table.Cell>
Matches any of the values specified in an array.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$nin`
</Table.Cell>
<Table.Cell>
Matches none of the values specified in an array.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$like`
</Table.Cell>
<Table.Cell>
Matches values containing a specified substring.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$lt`
</Table.Cell>
<Table.Cell>
Matches values that are less than a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$lte`
</Table.Cell>
<Table.Cell>
Matches values that are less than or equal to a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$gt`
</Table.Cell>
<Table.Cell>
Matches values that are greater than a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$gte`
</Table.Cell>
<Table.Cell>
Matches values that are greater than or equal to a specified value.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$re`
</Table.Cell>
<Table.Cell>
Matches values that match a specified regular expression.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$ilike`
</Table.Cell>
<Table.Cell>
Matches values containing a specified substring, case-insensitive.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$fulltext`
</Table.Cell>
<Table.Cell>
Performs a full-text search on a text property.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$overlap`
</Table.Cell>
<Table.Cell>
Matches values that have overlapping elements with the specified array.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$contains`
</Table.Cell>
<Table.Cell>
Performs an `@> value` comparison. Learn more in the [PostgreSQL documentation](https://www.postgresql.org/docs/9.6/functions-array.html).
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$contained`
</Table.Cell>
<Table.Cell>
Performs an `value @>` comparison. Learn more in the [PostgreSQL documentation](https://www.postgresql.org/docs/9.6/functions-array.html).
</Table.Cell>
</Table.Row>
<Table.Row className="bg-medusa-bg-component">
<Table.Cell colSpan={2}>
Logical Operators
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$and`
</Table.Cell>
<Table.Cell>
Joins two or more conditions with a logical AND.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$or`
</Table.Cell>
<Table.Cell>
Joins two or more conditions with a logical OR.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`$not`
</Table.Cell>
<Table.Cell>
Inverts the logic of a condition. For example, `$not: { $eq: value }` matches any value that is not equal to the specified value.
</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
+1 -1
View File
@@ -132,7 +132,7 @@ export const generatedEditDates = {
"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/tips/filtering/page.mdx": "2025-03-21T08:32:39.125Z",
"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",
"app/storefront-development/cart/create/page.mdx": "2025-03-27T14:46:51.473Z",
@@ -691,6 +691,50 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/create-medusa-app/page.mdx",
"pathname": "/create-medusa-app"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/methods/create/page.mdx",
"pathname": "/data-model-repository-reference/methods/create"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/methods/delete/page.mdx",
"pathname": "/data-model-repository-reference/methods/delete"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/methods/find/page.mdx",
"pathname": "/data-model-repository-reference/methods/find"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/methods/findAndCount/page.mdx",
"pathname": "/data-model-repository-reference/methods/findAndCount"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/methods/restore/page.mdx",
"pathname": "/data-model-repository-reference/methods/restore"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/methods/softDelete/page.mdx",
"pathname": "/data-model-repository-reference/methods/softDelete"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/methods/update/page.mdx",
"pathname": "/data-model-repository-reference/methods/update"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/methods/upsert/page.mdx",
"pathname": "/data-model-repository-reference/methods/upsert"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/methods/upsertWithReplace/page.mdx",
"pathname": "/data-model-repository-reference/methods/upsertWithReplace"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/page.mdx",
"pathname": "/data-model-repository-reference"
},
{
"filePath": "/www/apps/resources/app/data-model-repository-reference/tips/filtering/page.mdx",
"pathname": "/data-model-repository-reference/tips/filtering"
},
{
"filePath": "/www/apps/resources/app/deployment/medusa-application/railway/page.mdx",
"pathname": "/deployment/medusa-application/railway"
@@ -6367,6 +6367,137 @@ const generatedgeneratedReferencesSidebarSidebar = {
}
]
},
{
"loaded": true,
"isPathHref": true,
"type": "sidebar",
"sidebar_id": "data-model-repository-reference",
"title": "Data Model Repository",
"description": "List of methods in your service extending the data model repository.",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference",
"title": "Overview",
"children": []
},
{
"type": "separator"
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Methods",
"initialOpen": true,
"autogenerate_path": "/data-model-repository-reference/methods",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/methods/create",
"title": "create",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/methods/delete",
"title": "delete",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/methods/find",
"title": "find",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/methods/findAndCount",
"title": "findAndCount",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/methods/restore",
"title": "restore",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/methods/softDelete",
"title": "softDelete",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/methods/update",
"title": "update",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/methods/upsert",
"title": "upsert",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/methods/upsertWithReplace",
"title": "upsertWithReplace",
"description": "",
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Tips",
"initialOpen": true,
"autogenerate_path": "/data-model-repository-reference/tips",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/data-model-repository-reference/tips/filtering",
"title": "Filtering",
"description": "",
"children": []
}
]
}
]
},
{
"loaded": true,
"isPathHref": true,
@@ -75,6 +75,35 @@ export const referencesSidebar = [
},
],
},
{
type: "sidebar",
sidebar_id: "data-model-repository-reference",
title: "Data Model Repository",
description:
"List of methods in your service extending the data model repository.",
children: [
{
type: "link",
path: "/data-model-repository-reference",
title: "Overview",
},
{
type: "separator",
},
{
type: "category",
title: "Methods",
initialOpen: true,
autogenerate_path: "/data-model-repository-reference/methods",
},
{
type: "category",
title: "Tips",
initialOpen: true,
autogenerate_path: "/data-model-repository-reference/tips",
},
],
},
{
type: "link",
path: "/events-reference",
@@ -123,6 +123,7 @@ const sidebarMappings: {
"/references/workflows",
"/references-overview",
"/references/medusa-workflows",
"/data-model-repository-reference",
],
},
{
+5
View File
@@ -313,6 +313,11 @@ export const navDropdownItems: NavigationItem[] = [
title: "Data Model Language",
link: "/resources/references/data-model",
},
{
type: "link",
title: "Data Model Repository",
link: "/resources/data-model-repository-reference",
},
{
type: "link",
title: "Events Reference",