From 2060ba9ddb18b3eacd886732ee58bf2b217b0a30 Mon Sep 17 00:00:00 2001 From: Moroshani Date: Sat, 18 Jul 2026 11:59:07 +0330 Subject: [PATCH] docs(examples): add metadata filter operator snippets --- examples/javascript/README.md | 13 +++ examples/javascript/metadata-filters/and.ts | 16 +++ examples/javascript/metadata-filters/eq.ts | 14 +++ examples/javascript/metadata-filters/in.ts | 14 +++ examples/javascript/metadata-filters/near.ts | 14 +++ .../javascript/metadata-filters/shared.ts | 107 ++++++++++++++++++ examples/javascript/package.json | 4 + 7 files changed, 182 insertions(+) create mode 100644 examples/javascript/metadata-filters/and.ts create mode 100644 examples/javascript/metadata-filters/eq.ts create mode 100644 examples/javascript/metadata-filters/in.ts create mode 100644 examples/javascript/metadata-filters/near.ts create mode 100644 examples/javascript/metadata-filters/shared.ts diff --git a/examples/javascript/README.md b/examples/javascript/README.md index 470894e0..b562ca3a 100644 --- a/examples/javascript/README.md +++ b/examples/javascript/README.md @@ -54,6 +54,19 @@ Provision a fresh index (using the name supplied via `MOSS_INDEX_NAME`), push do npx tsx custom_embedding_sample.ts ``` +### Metadata Filter Operator Samples + +Create a temporary index with metadata-rich product documents, load it locally, +run one filtered query, then delete the temporary index. Each script focuses on +one operator so the filter object is easy to copy into another app. + +```bash +npm run metadata:eq +npm run metadata:and +npm run metadata:in +npm run metadata:near +``` + ### Session Sample Open a local-first `SessionIndex`, add documents in real time (no cloud round trip), query the in-memory index, then `pushIndex` to the cloud so another agent or device can resume it. This is how Moss indexes a live conversation. diff --git a/examples/javascript/metadata-filters/and.ts b/examples/javascript/metadata-filters/and.ts new file mode 100644 index 00000000..ff854e7e --- /dev/null +++ b/examples/javascript/metadata-filters/and.ts @@ -0,0 +1,16 @@ +import { runMetadataFilterExample } from "./shared"; + +runMetadataFilterExample({ + operator: "$and", + description: "Use $and to require multiple metadata filters to match together.", + query: "running shoes available in New York", + filter: { + $and: [ + { field: "category", condition: { $eq: "shoes" } }, + { field: "city", condition: { $eq: "new-york" } }, + ], + }, +}).catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/examples/javascript/metadata-filters/eq.ts b/examples/javascript/metadata-filters/eq.ts new file mode 100644 index 00000000..98cc4546 --- /dev/null +++ b/examples/javascript/metadata-filters/eq.ts @@ -0,0 +1,14 @@ +import { runMetadataFilterExample } from "./shared"; + +runMetadataFilterExample({ + operator: "$eq", + description: "Use $eq to match documents whose metadata field has one exact value.", + query: "running shoes for city training", + filter: { + field: "category", + condition: { $eq: "shoes" }, + }, +}).catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/examples/javascript/metadata-filters/in.ts b/examples/javascript/metadata-filters/in.ts new file mode 100644 index 00000000..2b044b07 --- /dev/null +++ b/examples/javascript/metadata-filters/in.ts @@ -0,0 +1,14 @@ +import { runMetadataFilterExample } from "./shared"; + +runMetadataFilterExample({ + operator: "$in", + description: "Use $in to match documents whose metadata value is in an allowed list.", + query: "portable gear for commuters", + filter: { + field: "city", + condition: { $in: ["new-york", "seattle"] }, + }, +}).catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/examples/javascript/metadata-filters/near.ts b/examples/javascript/metadata-filters/near.ts new file mode 100644 index 00000000..0d604fa9 --- /dev/null +++ b/examples/javascript/metadata-filters/near.ts @@ -0,0 +1,14 @@ +import { runMetadataFilterExample } from "./shared"; + +runMetadataFilterExample({ + operator: "$near", + description: "Use $near to match location metadata within a radius in meters.", + query: "city products near Times Square", + filter: { + field: "location", + condition: { $near: "40.7580,-73.9855,5000" }, + }, +}).catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/examples/javascript/metadata-filters/shared.ts b/examples/javascript/metadata-filters/shared.ts new file mode 100644 index 00000000..f08b2822 --- /dev/null +++ b/examples/javascript/metadata-filters/shared.ts @@ -0,0 +1,107 @@ +import { MossClient, type DocumentInfo } from "@moss-dev/moss"; +import { config } from "dotenv"; + +config(); + +type MetadataFilter = Record; + +interface MetadataFilterExample { + operator: string; + description: string; + query: string; + filter: MetadataFilter; +} + +const documents: DocumentInfo[] = [ + { + id: "shoe-nyc-001", + text: "Breathable road running shoes for daily city training.", + metadata: { + category: "shoes", + brand: "swiftfit", + city: "new-york", + location: "40.7580,-73.9855", + }, + }, + { + id: "shoe-denver-002", + text: "Trail running shoes built for rocky mountain paths.", + metadata: { + category: "shoes", + brand: "peakstride", + city: "denver", + location: "39.7392,-104.9903", + }, + }, + { + id: "bag-nyc-003", + text: "Lightweight commuter backpack with a laptop sleeve.", + metadata: { + category: "bags", + brand: "urbanpack", + city: "new-york", + location: "40.7505,-73.9934", + }, + }, + { + id: "bag-seattle-004", + text: "Compact travel duffel with a separate shoe compartment.", + metadata: { + category: "bags", + brand: "swiftfit", + city: "seattle", + location: "47.6205,-122.3493", + }, + }, +]; + +function requireEnv(name: string): string { + const value = process.env[name]?.trim(); + + if (!value) { + throw new Error(`Missing ${name}. Add it to .env before running this example.`); + } + + return value; +} + +export async function runMetadataFilterExample(example: MetadataFilterExample): Promise { + const projectId = requireEnv("MOSS_PROJECT_ID"); + const projectKey = requireEnv("MOSS_PROJECT_KEY"); + const indexName = `metadata-filter-${example.operator.slice(1)}-${Date.now()}`; + const client = new MossClient(projectId, projectKey); + let indexCreated = false; + + try { + console.log(`Moss metadata filter example: ${example.operator}`); + console.log(example.description); + + console.log(`\nCreating temporary index: ${indexName}`); + await client.createIndex(indexName, documents, { modelId: "moss-minilm" }); + indexCreated = true; + + console.log("Loading index locally for filtered query..."); + await client.loadIndex(indexName); + + console.log(`\nQuery: ${example.query}`); + console.log(`Filter: ${JSON.stringify(example.filter)}`); + + const results = await client.query(indexName, example.query, { + topK: 5, + alpha: 0.5, + filter: example.filter, + }); + + console.log(`\nFound ${results.docs.length} result(s) in ${results.timeTakenInMs}ms:`); + results.docs.forEach((doc, index) => { + const preview = doc.text.length > 80 ? `${doc.text.slice(0, 80)}...` : doc.text; + console.log(`${index + 1}. [${doc.id}] score=${doc.score.toFixed(3)} ${preview}`); + console.log(` metadata=${JSON.stringify(doc.metadata ?? {})}`); + }); + } finally { + if (indexCreated) { + console.log(`\nDeleting temporary index: ${indexName}`); + await client.deleteIndex(indexName); + } + } +} diff --git a/examples/javascript/package.json b/examples/javascript/package.json index 9de30e45..d8f4911a 100644 --- a/examples/javascript/package.json +++ b/examples/javascript/package.json @@ -39,6 +39,10 @@ "session": "tsx session_sample.ts", "session-cache": "tsx session_cache_sample.ts", "session-custom-auth": "tsx session_custom_auth_sample.ts", + "metadata:eq": "tsx metadata-filters/eq.ts", + "metadata:and": "tsx metadata-filters/and.ts", + "metadata:in": "tsx metadata-filters/in.ts", + "metadata:near": "tsx metadata-filters/near.ts", "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": {