Metadata Filtering in Query
Currently, Query doesn't support filtering by nested JSON properties in metadata fields using query.graph.
Why This Limitation Exists#
Metadata fields in Medusa are stored as JSON/JSONB columns in PostgreSQL. While PostgreSQL supports querying JSON fields, Query's abstraction layer doesn't currently expose this functionality through the standard filtering interface.
For example, this won't work:
Workarounds#
Option 1: Filter After Retrieval#
For infrequent queries, retrieve the data with Query first, then filter the results in memory:
This approach is less efficient for large datasets since all records are loaded into memory first.
Option 2: Use Module Service Directly#
You can also bypass Query and use the module service directly to leverage PostgreSQL's JSONB querying capabilities. The downside to this approach is that you can't retrieve data across modules.
For example, to filter orders by metadata using the Order Module Service:
1import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"2import { Modules } from "@medusajs/framework/utils"3import { IOrderModuleService } from "@medusajs/framework/types"4 5export const GET = async (6 req: MedusaRequest,7 res: MedusaResponse8) => {9 const orderModuleService: IOrderModuleService = req.scope.resolve(10 Modules.ORDER11 )12 13 const orders = await orderModuleService.listOrders({14 metadata: {15 carePlanId: "123",16 },17 })18 19 res.json({ orders })20}
You can also combine this with Query to retrieve related data across modules. For example:
1import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"2import {3 Modules,4 ContainerRegistrationKeys,5} from "@medusajs/framework/utils"6import { IOrderModuleService } from "@medusajs/framework/types"7 8export const GET = async (9 req: MedusaRequest,10 res: MedusaResponse11) => {12 const orderModuleService: IOrderModuleService = req.scope.resolve(13 Modules.ORDER14 )15 const query = req.scope.resolve(16 ContainerRegistrationKeys.QUERY17 )18 19 // Step 1: Use the module service to get order IDs matching the metadata filter20 const orderIds = await orderModuleService.listOrders({21 metadata: {22 carePlanId: "123",23 },24 }, {25 select: ["id"],26 })27 28 // Step 2: Use Query to get related data for those orders29 const { data: orders } = await query.graph({30 entity: "order",31 fields: ["id", "metadata", "customer.id"],32 filters: {33 id: orderIds.map((o) => o.id),34 },35 })36 37 res.json({ orders })38}