diff --git a/apps/docs/changelog/developer-platform.mdx b/apps/docs/changelog/developer-platform.mdx index 62d610e8..98a75d6f 100644 --- a/apps/docs/changelog/developer-platform.mdx +++ b/apps/docs/changelog/developer-platform.mdx @@ -6,6 +6,10 @@ description: "API updates, new endpoints, and SDK releases" API updates, new endpoints, SDK releases, and developer-focused features. +## October 27, 2025 + +- **Enhanced Filtering Capabilities:** Major improvements to the search filtering API with new `string_contains` filter type for partial string matching, `ignoreCase` option for case-insensitive string operations, and improved negation support across all filter types including proper numeric equality negation. The implementation also includes enhanced SQL injection protection and wildcard escaping for improved security. + ## September 17, 2025 - **Forgotten Memories Search:** New `include.forgottenMemories` parameter in v4 search API allows searching through memories that have been explicitly forgotten or expired. Set to `true` to include forgotten memories in search results, helping recover previously archived information. diff --git a/apps/docs/search/filtering.mdx b/apps/docs/search/filtering.mdx index c20f4f2c..a9efecba 100644 --- a/apps/docs/search/filtering.mdx +++ b/apps/docs/search/filtering.mdx @@ -1,63 +1,85 @@ --- -title: "Grouping and filtering" -description: "Container tags, metadata filters, and advanced search filtering techniques" +title: "Filtering Memories" +description: "Filter and search memories using container tags and metadata" icon: "filter" --- +Supermemory provides two complementary filtering mechanisms that work independently or together to help you find exactly what you need. -Supermemory supports filtering search results using container tags, metadata conditions, and advanced filtering techniques for both `/v3/search` and `/v4/search` endpoints. +## How Filtering Works + +Supermemory uses two types of filters for different purposes: + + + + **Organize memories** into isolated spaces by user, project, or workspace + + + **Query memories** by custom properties like category, status, or date + + + +Both filtering types can be used: +- **Independently** - Use container tags alone OR metadata filters alone +- **Together** - Combine both for precise filtering (most common) + +Think of it as: `[Container Tags] → [Your Memories] ← [Metadata Filters]` ## Container Tags -Container tags group memories by user, project, or organization. They're the primary way to isolate search results. +Container tags create isolated memory spaces. They're perfect for multi-tenant applications, user profiles, and project organization. -**Important**: Container tags use **exact array matching**. A document with `["technology", "quantum-computing"]` will NOT match a search for `["technology"]`. The arrays must be identical. +### How Container Tags Work -### Document Search (v3/search) +- **Exact matching**: Arrays must match exactly. A memory tagged with `["user_123", "project_ai"]` will NOT match a search for just `["user_123"]` +- **Isolation**: Each container tag combination creates a separate knowledge graph +- **Naming patterns**: Use consistent patterns like `user_{id}`, `project_{id}`, or `org_{id}_team_{id}` + +### Basic Usage ```typescript - // Single container tag + // Search within a user's memories const results = await client.search.documents({ - q: "machine learning", + q: "machine learning notes", containerTags: ["user_123"], limit: 10 }); - // Multiple container tags - const results2 = await client.search.documents({ - q: "project status", - containerTags: ["project_ai", "team_research"], + // Search within a project + const projectResults = await client.search.documents({ + q: "requirements", + containerTags: ["project_ai"], limit: 10 }); ``` ```python - # Single container tag + # Search within a user's memories results = client.search.documents( - q="machine learning", + q="machine learning notes", container_tags=["user_123"], limit=10 ) - # Multiple container tags - results2 = client.search.documents( - q="project status", - container_tags=["project_ai", "team_research"], + # Search within a project + project_results = client.search.documents( + q="requirements", + container_tags=["project_ai"], limit=10 ) ``` ```bash - # Single container tag + # Search within a user's memories curl -X POST "https://api.supermemory.ai/v3/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "q": "machine learning", + "q": "machine learning notes", "containerTags": ["user_123"], "limit": 10 }' @@ -65,66 +87,352 @@ Container tags group memories by user, project, or organization. They're the pri -### Memory Search (v4/search) +### Container Tag Patterns + + +**Best Practice**: Use single container tags when possible. Multi-tag arrays require exact matching, which can be restrictive. + + +#### Recommended Patterns +- User isolation: `user_{userId}` +- Project grouping: `project_{projectId}` +- Workspace separation: `workspace_{workspaceId}` +- Hierarchical: `org_{orgId}_team_{teamId}` +- Temporal: `user_{userId}_2024_q1` + +#### API Differences + +| Endpoint | Field Name | Type | Example | +|----------|------------|------|---------| +| `/v3/search` | `containerTags` | Array | `["user_123"]` | +| `/v4/search` | `containerTag` | String | `"user_123"` | +| `/v3/documents/list` | `containerTags` | Array | `["user_123"]` | + +## Metadata Filtering + +Metadata filters let you query memories by any custom property. They use SQL-like AND/OR logic with explicit grouping. + +### Filter Structure + +All metadata filters must be wrapped in AND or OR arrays: + +```javascript +// ✅ Correct - wrapped in AND array +filters: { + AND: [ + { key: "category", value: "tech", negate: false } + ] +} + +// ❌ Wrong - not wrapped +filters: { + key: "category", value: "tech", negate: false +} +``` + +### Why Explicit Grouping? + +Without explicit grouping, this SQL query is ambiguous: +```sql +category = 'tech' OR status = 'published' AND priority = 'high' +``` + +Our structure forces clarity: +```javascript +// Clear: (category = 'tech') OR (status = 'published' AND priority = 'high') +{ + OR: [ + { key: "category", value: "tech" }, + { AND: [ + { key: "status", value: "published" }, + { key: "priority", value: "high" } + ]} + ] +} +``` + +### Basic Metadata Filtering ```typescript - // Note: singular "containerTag" for v4/search - const results = await client.search.memories({ - q: "research findings", - containerTag: "user_123", // Single string, not array - limit: 5 + // Single condition + const results = await client.search.documents({ + q: "neural networks", + filters: { + AND: [ + { key: "category", value: "ai", negate: false } + ] + }, + limit: 10 + }); + + // Multiple AND conditions + const filtered = await client.search.documents({ + q: "research", + filters: { + AND: [ + { key: "category", value: "science", negate: false }, + { key: "status", value: "published", negate: false }, + { key: "year", value: "2024", negate: false } + ] + }, + limit: 10 }); ``` ```python - # Note: singular "container_tag" for v4/search - results = client.search.memories( - q="research findings", - container_tag="user_123", # Single string, not array - limit=5 + # Single condition + results = client.search.documents( + q="neural networks", + filters={ + "AND": [ + {"key": "category", "value": "ai", "negate": False} + ] + }, + limit=10 + ) + + # Multiple AND conditions + filtered = client.search.documents( + q="research", + filters={ + "AND": [ + {"key": "category", "value": "science", "negate": False}, + {"key": "status", "value": "published", "negate": False}, + {"key": "year", "value": "2024", "negate": False} + ] + }, + limit=10 ) ``` ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ + # Single condition + curl -X POST "https://api.supermemory.ai/v3/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "q": "research findings", - "containerTag": "user_123", - "limit": 5 + "q": "neural networks", + "filters": { + "AND": [ + {"key": "category", "value": "ai", "negate": false} + ] + }, + "limit": 10 }' ``` +## Filter Types in Detail + +Supermemory supports four filter types, each designed for specific use cases. + +### 1. String Equality (Default) + +Exact string matching with optional case-insensitive comparison. + + + + ```javascript + // Case-sensitive exact match (default) + { + key: "status", + value: "Published", + negate: false + } + ``` + + + ```javascript + // Matches "published", "Published", "PUBLISHED" + { + key: "status", + value: "PUBLISHED", + ignoreCase: true, + negate: false + } + ``` + + + ```javascript + // Exclude specific status + { + key: "status", + value: "draft", + negate: true + } + ``` + + + +### 2. String Contains + +Search for substrings within text fields. + + + + ```javascript + // Find all documents containing "machine learning" + { + filterType: "string_contains", + key: "description", + value: "machine learning", + negate: false + } + ``` + + + ```javascript + // Case-insensitive substring search + { + filterType: "string_contains", + key: "title", + value: "NEURAL", + ignoreCase: true, + negate: false + } + ``` + + + ```javascript + // Exclude documents containing "deprecated" + { + filterType: "string_contains", + key: "content", + value: "deprecated", + negate: true + } + ``` + + + +### 3. Numeric Comparisons + +Filter by numeric values with comparison operators. + + + + ```javascript + // Greater than or equal + { + filterType: "numeric", + key: "score", + value: "80", + numericOperator: ">=", + negate: false + } + + // Less than + { + filterType: "numeric", + key: "readingTime", + value: "10", + numericOperator: "<", + negate: false + } + ``` + + + ```javascript + // NOT equal to 5 (becomes !=) + { + filterType: "numeric", + key: "priority", + value: "5", + numericOperator: "=", + negate: true + } + + // NOT less than 80 (becomes >=) + { + filterType: "numeric", + key: "score", + value: "80", + numericOperator: "<", + negate: true + } + ``` + + + -**Container Tag Differences**: -- `/v3/search` uses `containerTags` (plural array) with exact array matching -- `/v4/search` uses `containerTag` (singular string) for single tag filtering -- Exact matching means `["user", "project"]` ≠ `["user"]` +**Numeric Negation Mapping**: +When using `negate: true` with numeric filters, operators are reversed: +- `<` → `>=` +- `<=` → `>` +- `>` → `<=` +- `>=` → `<` +- `=` → `!=` -## Basic Metadata Filtering +### 4. Array Contains -Filter by metadata fields with simple conditions: +Check if an array field contains a specific value. + + + + ```javascript + // Find documents with specific participant + { + filterType: "array_contains", + key: "participants", + value: "john.doe", + negate: false + } + ``` + + + ```javascript + // Exclude documents with specific tag + { + filterType: "array_contains", + key: "tags", + value: "archived", + negate: true + } + ``` + + + ```javascript + // Must have both participants (use AND) + { + AND: [ + { + filterType: "array_contains", + key: "participants", + value: "project.manager" + }, + { + filterType: "array_contains", + key: "participants", + value: "lead.developer" + } + ] + } + ``` + + + +## Common Patterns + +Ready-to-use filtering patterns for common scenarios. + +### User-Specific Content with Category ```typescript const results = await client.search.documents({ - q: "artificial intelligence", + q: "project updates", + containerTags: ["user_123"], filters: { AND: [ - { - key: "category", - value: "technology", - negate: false - } + { key: "category", value: "work", negate: false }, + { key: "visibility", value: "private", negate: false } ] }, limit: 10 @@ -134,755 +442,45 @@ Filter by metadata fields with simple conditions: ```python results = client.search.documents( - q="artificial intelligence", + q="project updates", + container_tags=["user_123"], filters={ "AND": [ - { - "key": "category", - "value": "technology", - "negate": False - } + {"key": "category", "value": "work", "negate": False}, + {"key": "visibility", "value": "private", "negate": False} ] }, limit=10 ) ``` - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "artificial intelligence", - "filters": { - "AND": [ - { - "key": "category", - "value": "technology", - "negate": false - } - ] - }, - "limit": 10 - }' - ``` - -## Numeric Filtering - -Filter by numeric values with operators: +### Recent High-Priority Content ```typescript const results = await client.search.documents({ - q: "research papers", + q: "important tasks", filters: { AND: [ { filterType: "numeric", - key: "readingTime", - value: "10", - numericOperator: "<=", + key: "priority", + value: "7", + numericOperator: ">=", negate: false }, { filterType: "numeric", - key: "wordCount", - value: "1000", + key: "created_timestamp", + value: "1704067200", // 2024-01-01 numericOperator: ">=", negate: false } ] }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="research papers", - filters={ - "AND": [ - { - "filterType": "numeric", - "key": "readingTime", - "value": "10", - "numericOperator": "<=", - "negate": False - }, - { - "filterType": "numeric", - "key": "wordCount", - "value": "1000", - "numericOperator": ">=", - "negate": False - } - ] - }, - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "research papers", - "filters": { - "AND": [ - { - "filterType": "numeric", - "key": "readingTime", - "value": "10", - "numericOperator": "<=", - "negate": false - }, - { - "filterType": "numeric", - "key": "wordCount", - "value": "1000", - "numericOperator": ">=", - "negate": false - } - ] - }, - "limit": 10 - }' - ``` - - - -## Array Contains Filtering - -Filter by array values like participants, tags, or categories. The `array_contains` filter type checks if an array field contains a specific value. - -### Basic Array Contains - - - - ```typescript - const results = await client.search.documents({ - q: "meeting notes", - filters: { - AND: [ - { - key: "participants", - value: "john.doe", - filterType: "array_contains" - } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="meeting notes", - filters={ - "AND": [ - { - "key": "participants", - "value": "john.doe", - "filterType": "array_contains" - } - ] - }, - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "meeting notes", - "filters": { - "AND": [ - { - "key": "participants", - "value": "john.doe", - "filterType": "array_contains" - } - ] - }, - "limit": 10 - }' - ``` - - - -### Array Contains with Negation - -Exclude documents that contain specific values in arrays: - - - - ```typescript - const results = await client.search.documents({ - q: "team meetings", - filters: { - AND: [ - { - key: "participants", - value: "john.doe", - filterType: "array_contains", - negate: true // Exclude meetings with john.doe - } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="team meetings", - filters={ - "AND": [ - { - "key": "participants", - "value": "john.doe", - "filterType": "array_contains", - "negate": True # Exclude meetings with john.doe - } - ] - }, - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "team meetings", - "filters": { - "AND": [ - { - "key": "participants", - "value": "john.doe", - "filterType": "array_contains", - "negate": true - } - ] - }, - "limit": 10 - }' - ``` - - - -### Multiple Array Contains Conditions - -Find documents with multiple required participants: - - - - ```typescript - const results = await client.search.documents({ - q: "project planning", - filters: { - AND: [ - { - key: "participants", - value: "project.manager", - filterType: "array_contains" - }, - { - key: "participants", - value: "lead.developer", - filterType: "array_contains" - }, - { - key: "tags", - value: "urgent", - filterType: "array_contains" - } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="project planning", - filters={ - "AND": [ - { - "key": "participants", - "value": "project.manager", - "filterType": "array_contains" - }, - { - "key": "participants", - "value": "lead.developer", - "filterType": "array_contains" - }, - { - "key": "tags", - "value": "urgent", - "filterType": "array_contains" - } - ] - }, - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "project planning", - "filters": { - "AND": [ - { - "key": "participants", - "value": "project.manager", - "filterType": "array_contains" - }, - { - "key": "participants", - "value": "lead.developer", - "filterType": "array_contains" - }, - { - "key": "tags", - "value": "urgent", - "filterType": "array_contains" - } - ] - }, - "limit": 10 - }' - ``` - - - -### Array Contains with OR Logic - -Find documents with any of several participants: - - - - ```typescript - const results = await client.search.documents({ - q: "weekly reports", - filters: { - OR: [ - { - key: "reviewers", - value: "senior.manager", - filterType: "array_contains" - }, - { - key: "reviewers", - value: "department.head", - filterType: "array_contains" - }, - { - key: "reviewers", - value: "project.lead", - filterType: "array_contains" - } - ] - }, - limit: 15 - }); - ``` - - - ```python - results = client.search.documents( - q="weekly reports", - filters={ - "OR": [ - { - "key": "reviewers", - "value": "senior.manager", - "filterType": "array_contains" - }, - { - "key": "reviewers", - "value": "department.head", - "filterType": "array_contains" - }, - { - "key": "reviewers", - "value": "project.lead", - "filterType": "array_contains" - } - ] - }, - limit=15 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "weekly reports", - "filters": { - "OR": [ - { - "key": "reviewers", - "value": "senior.manager", - "filterType": "array_contains" - }, - { - "key": "reviewers", - "value": "department.head", - "filterType": "array_contains" - }, - { - "key": "reviewers", - "value": "project.lead", - "filterType": "array_contains" - } - ] - }, - "limit": 15 - }' - ``` - - - -## OR Conditions - -Combine multiple conditions with OR logic: - - - - ```typescript - const results = await client.search.documents({ - q: "technology updates", - filters: { - OR: [ - { - key: "category", - value: "ai", - negate: false - }, - { - key: "category", - value: "machine-learning", - negate: false - }, - { - key: "topic", - value: "neural-networks", - negate: false - } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="technology updates", - filters={ - "OR": [ - { - "key": "category", - "value": "ai", - "negate": False - }, - { - "key": "category", - "value": "machine-learning", - "negate": False - }, - { - "key": "topic", - "value": "neural-networks", - "negate": False - } - ] - }, - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "technology updates", - "filters": { - "OR": [ - { - "key": "category", - "value": "ai", - "negate": false - }, - { - "key": "category", - "value": "machine-learning", - "negate": false - }, - { - "key": "topic", - "value": "neural-networks", - "negate": false - } - ] - }, - "limit": 10 - }' - ``` - - - -## Complex Nested Conditions - -Combine AND and OR logic for advanced filtering: - - - - ```typescript - const results = await client.search.documents({ - q: "research publications", - filters: { - AND: [ - { - key: "status", - value: "published", - negate: false - }, - { - OR: [ - { - key: "category", - value: "ai", - negate: false - }, - { - key: "category", - value: "machine-learning", - negate: false - } - ] - }, - { - filterType: "numeric", - key: "year", - value: "2023", - numericOperator: ">=", - negate: false - } - ] - }, - limit: 15 - }); - ``` - - - ```python - results = client.search.documents( - q="research publications", - filters={ - "AND": [ - { - "key": "status", - "value": "published", - "negate": False - }, - { - "OR": [ - { - "key": "category", - "value": "ai", - "negate": False - }, - { - "key": "category", - "value": "machine-learning", - "negate": False - } - ] - }, - { - "filterType": "numeric", - "key": "year", - "value": "2023", - "numericOperator": ">=", - "negate": False - } - ] - }, - limit=15 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "research publications", - "filters": { - "AND": [ - { - "key": "status", - "value": "published", - "negate": false - }, - { - "OR": [ - { - "key": "category", - "value": "ai", - "negate": false - }, - { - "key": "category", - "value": "machine-learning", - "negate": false - } - ] - }, - { - "filterType": "numeric", - "key": "year", - "value": "2023", - "numericOperator": ">=", - "negate": false - } - ] - }, - "limit": 15 - }' - ``` - - - -## Negation Filters - -Exclude specific values with negation: - - - - ```typescript - const results = await client.search.documents({ - q: "machine learning", - filters: { - AND: [ - { - key: "category", - value: "ai", - negate: false - }, - { - key: "status", - value: "draft", - negate: true // Exclude drafts - }, - { - key: "author", - value: "deprecated_user", - negate: true // Exclude specific author - } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="machine learning", - filters={ - "AND": [ - { - "key": "category", - "value": "ai", - "negate": False - }, - { - "key": "status", - "value": "draft", - "negate": True # Exclude drafts - }, - { - "key": "author", - "value": "deprecated_user", - "negate": True # Exclude specific author - } - ] - }, - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning", - "filters": { - "AND": [ - { - "key": "category", - "value": "ai", - "negate": false - }, - { - "key": "status", - "value": "draft", - "negate": true - }, - { - "key": "author", - "value": "deprecated_user", - "negate": true - } - ] - }, - "limit": 10 - }' - ``` - - - -## Document-Specific Search - -Search within a specific document: - - - - ```typescript - const results = await client.search.documents({ - q: "neural network architecture", - docId: "doc_large_textbook_123", // Search only within this document limit: 20 }); ``` @@ -890,170 +488,415 @@ Search within a specific document: ```python results = client.search.documents( - q="neural network architecture", - doc_id="doc_large_textbook_123", # Search only within this document + q="important tasks", + filters={ + "AND": [ + { + "filterType": "numeric", + "key": "priority", + "value": "7", + "numericOperator": ">=", + "negate": False + }, + { + "filterType": "numeric", + "key": "created_timestamp", + "value": "1704067200", # 2024-01-01 + "numericOperator": ">=", + "negate": False + } + ] + }, limit=20 ) ``` - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "neural network architecture", - "docId": "doc_large_textbook_123", - "limit": 20 - }' + + +### Team Collaboration Filter + + + + ```typescript + const results = await client.search.documents({ + q: "meeting notes", + containerTags: ["project_alpha"], + filters: { + AND: [ + { + OR: [ + { + filterType: "array_contains", + key: "participants", + value: "alice" + }, + { + filterType: "array_contains", + key: "participants", + value: "bob" + } + ] + }, + { + key: "type", + value: "meeting", + negate: false + } + ] + }, + limit: 15 + }); + ``` + + + ```python + results = client.search.documents( + q="meeting notes", + container_tags=["project_alpha"], + filters={ + "AND": [ + { + "OR": [ + { + "filterType": "array_contains", + "key": "participants", + "value": "alice" + }, + { + "filterType": "array_contains", + "key": "participants", + "value": "bob" + } + ] + }, + { + "key": "type", + "value": "meeting", + "negate": False + } + ] + }, + limit=15 + ) ``` -## Filter Best Practices +### Exclude Drafts and Deprecated Content - -**Performance Tips**: -- Use container tags as the primary filter (fastest) -- Combine with simple metadata filters for precision -- Avoid complex nested OR conditions for better performance -- Use numeric operators only when necessary - - - -**Filter Structure**: All conditions must be wrapped in `AND` or `OR` arrays. Single conditions still need the array wrapper: `{"AND": [{"key": "category", "value": "ai"}]}`. - - - -**Supported Operators**: -- **String**: Exact matching only -- **Numeric**: `<=`, `>=`, `<`, `>`, `=` -- **Array**: `array_contains` for checking if array contains value -- **Negation**: Works with all filter types - - -## Common Filter Patterns - -### User-Specific Content -```json -{ - "containerTags": ["user_123"], - "filters": { - "AND": [ - {"key": "visibility", "value": "private", "negate": false} - ] - } -} -``` - -### Recent High-Quality Content -```json -{ - "filters": { - "AND": [ - { - "filterType": "numeric", - "key": "created_year", - "value": "2024", - "numericOperator": ">=" - }, - { - "filterType": "numeric", - "key": "quality_score", - "value": "7", - "numericOperator": ">=" - } - ] - } -} -``` - -### Multi-Category Search -```json -{ - "filters": { - "OR": [ - {"key": "category", "value": "ai"}, - {"key": "category", "value": "machine-learning"}, - {"key": "category", "value": "data-science"} - ] - } -} -``` - -### Team Member Participation -```json -{ - "filters": { - "AND": [ - { - "key": "participants", - "value": "team.lead", - "filterType": "array_contains" - }, - { - "key": "project_tags", - "value": "high-priority", - "filterType": "array_contains" - } - ] - } -} -``` - -### Exclude Specific Teams -```json -{ - "filters": { - "AND": [ - { - "key": "department", - "value": "marketing", - "filterType": "array_contains", - "negate": true - }, - { - "key": "confidential_tags", - "value": "executive-only", - "filterType": "array_contains", - "negate": true - } - ] - } -} -``` - -### Complex Meeting Filter -```json -{ - "filters": { - "AND": [ - { - "OR": [ + + + ```typescript + const results = await client.search.documents({ + q: "documentation", + filters: { + AND: [ { - "key": "attendees", - "value": "ceo", - "filterType": "array_contains" + key: "status", + value: "draft", + negate: true // Exclude drafts }, { - "key": "attendees", - "value": "cto", - "filterType": "array_contains" + filterType: "string_contains", + key: "content", + value: "deprecated", + negate: true // Exclude deprecated + }, + { + filterType: "array_contains", + key: "tags", + value: "archived", + negate: true // Exclude archived } ] }, - { - "key": "meeting_type", - "value": "cancelled", - "negate": true - }, - { - "filterType": "numeric", - "key": "duration_minutes", - "value": "30", - "numericOperator": ">=" - } - ] - } -} + limit: 10 + }); + ``` + + + ```python + results = client.search.documents( + q="documentation", + filters={ + "AND": [ + { + "key": "status", + "value": "draft", + "negate": True # Exclude drafts + }, + { + "filterType": "string_contains", + "key": "content", + "value": "deprecated", + "negate": True # Exclude deprecated + }, + { + "filterType": "array_contains", + "key": "tags", + "value": "archived", + "negate": True # Exclude archived + } + ] + }, + limit=10 + ) + ``` + + + +## API-Specific Notes + +Different endpoints have slightly different requirements: + +| Endpoint | Container Tag Field | Type | Filter Format | Notes | +|----------|---------------------|------|---------------|-------| +| `/v3/search` | `containerTags` | Array | JSON object | Document search | +| `/v4/search` | `containerTag` | String | JSON object | Memory search | +| `/v3/documents/list` | `containerTags` | Array | **JSON string** | Must use `JSON.stringify()` | + + +**List API Special Requirement**: The `/v3/documents/list` endpoint requires filters as a JSON string: + +```javascript +// ✅ Correct for List API +filters: JSON.stringify({ AND: [...] }) + +// ❌ Wrong for List API (but correct for Search API) +filters: { AND: [...] } ``` + + +## Combining Container Tags and Metadata + +Most real-world applications combine both filtering types for precise control. + +### Example: User's Work Documents from 2024 + + + + ```typescript + const results = await client.search.documents({ + q: "quarterly report", + containerTags: ["user_123"], // User isolation + filters: { + AND: [ + { key: "category", value: "work" }, + { key: "type", value: "report" }, + { + filterType: "numeric", + key: "year", + value: "2024", + numericOperator: "=" + } + ] + }, + limit: 10 + }); + ``` + + + ```python + results = client.search.documents( + q="quarterly report", + container_tags=["user_123"], # User isolation + filters={ + "AND": [ + {"key": "category", "value": "work"}, + {"key": "type", "value": "report"}, + { + "filterType": "numeric", + "key": "year", + "value": "2024", + "numericOperator": "=" + } + ] + }, + limit=10 + ) + ``` + + + +### Example: Project's Active High-Priority Tasks + + + + ```typescript + const results = await client.search.documents({ + q: "implementation", + containerTags: ["project_alpha"], // Project isolation + filters: { + AND: [ + { + key: "status", + value: "completed", + negate: true // Not completed + }, + { + filterType: "numeric", + key: "priority", + value: "7", + numericOperator: ">=", + negate: false + }, + { + filterType: "array_contains", + key: "assignees", + value: "current_user" + } + ] + }, + limit: 20 + }); + ``` + + + ```python + results = client.search.documents( + q="implementation", + container_tags=["project_alpha"], # Project isolation + filters={ + "AND": [ + { + "key": "status", + "value": "completed", + "negate": True # Not completed + }, + { + "filterType": "numeric", + "key": "priority", + "value": "7", + "numericOperator": ">=", + "negate": False + }, + { + "filterType": "array_contains", + "key": "assignees", + "value": "current_user" + } + ] + }, + limit=20 + ) + ``` + + + +## Document-Specific Search + +Search within a single large document using the `docId` parameter: + + + + ```typescript + // Search within a specific book or manual + const results = await client.search.documents({ + q: "neural architecture", + docId: "doc_textbook_ml_2024", + limit: 20 + }); + ``` + + + ```python + # Search within a specific book or manual + results = client.search.documents( + q="neural architecture", + doc_id="doc_textbook_ml_2024", + limit=20 + ) + ``` + + + +Use this for: +- Large textbooks or manuals +- Multi-chapter books +- Long podcast transcripts +- Course materials + +## Validation & Limits + +### Metadata Key Requirements +- **Pattern**: `/^[a-zA-Z0-9_.-]+$/` +- **Allowed**: Letters, numbers, underscore, hyphen, dot +- **Max length**: 64 characters +- **No spaces or special characters** + +### Valid vs Invalid Keys +```javascript +// ✅ Valid keys +"user_email" +"created-date" +"version.number" +"priority_level_2" + +// ❌ Invalid keys +"user email" // Spaces not allowed +"created@date" // @ not allowed +"priority!" // ! not allowed +"very_long_key_name_that_exceeds_64_characters_limit" // Too long +``` + +### Query Complexity Limits +- **Maximum conditions**: 200 per query +- **Maximum nesting depth**: 8 levels +- **Container tag arrays**: Must match exactly + +## Troubleshooting + +### No Results Returned + + + + **Problem**: Container tags must match exactly as arrays. + + **Solution**: Verify the exact array structure. `["user_123"]` ≠ `["user_123", "project_1"]` + + + **Problem**: Keys are case-sensitive by default. + + **Solution**: Check exact key spelling and casing, or use `ignoreCase: true` for values. + + + **Problem**: Using `negate: true` when you meant `false`. + + **Solution**: Review your negate values. `false` = include, `true` = exclude. + + + +### Validation Errors + + + + **Error**: "Invalid metadata key: contains unsafe characters" + + **Solution**: Remove spaces, special characters. Use only alphanumeric, underscore, hyphen, dot. + + + **Error**: "Invalid filter structure" + + **Solution**: Ensure all conditions are wrapped in AND or OR arrays. + + + **Error**: "Invalid filter format" + + **Solution**: For `/v3/documents/list`, use `JSON.stringify()` on the filter object. + + + +### Performance Issues + + + + **Problem**: Complex nested OR conditions with many branches. + + **Solution**: Simplify logic, reduce nesting, or split into multiple queries. + + + **Problem**: "Query exceeds maximum complexity" + + **Solution**: Reduce conditions (max 200) or nesting depth (max 8). + + \ No newline at end of file