Metadata Filtering Guide
Overview
LocalVectorDB provides a powerful and secure metadata filtering system that allows you to query documents based on their metadata fields. The filtering system supports MongoDB-style operators and generates safe parameterized SQL queries to prevent injection attacks.
Important
Metadata fields must be declared in the database’s metadata_schema to be stored and
queryable. Each declared field becomes a real column on the documents table. Any key you pass
in a document’s metadata that is not part of the schema is dropped on insert with a logged
warning (it is not stored, and you cannot filter on it). Likewise, filtering on a field that is not
in the schema raises an error. Declare every field you intend to store, filter, or sort on when you
create the database (or add it later with update_metadata_schema()).
Key Features
Secure by design - All queries use parameterized SQL
MongoDB-style operators for intuitive querying
Logical operators for complex conditions
Type-safe operations with schema validation
JSON/Array support for complex data structures
Performance optimized with proper indexing
Multi-column embeddings - Enable vector search on metadata fields
Full-text search - FTS5 support for metadata fields
Metadata Field Attributes
When defining metadata fields, you can specify several attributes:
Attribute |
Default |
Description |
|---|---|---|
|
Required |
Field type: TEXT, INTEGER, REAL, BOOLEAN, DATE, or JSON |
|
False |
Create database index for faster filtering |
|
False |
Field must be provided when adding documents |
|
None |
Default value for optional fields |
|
False |
Generate embeddings for vector search (TEXT/JSON only) |
|
False |
Enable full-text search with FTS5 (TEXT only) |
Predefined Schema Templates
Instead of hand-writing a schema, you can start from one of several built-in
templates via get_common_metadata_schemas(). Pass the
template name directly as the metadata_schema argument when creating a
database:
from localvectordb import VectorDB
# Use the built-in "research_papers" schema (title, authors, abstract,
# publication_date, journal, doi, keywords, citation_count)
db = VectorDB("papers", "./storage", metadata_schema="research_papers")
The available templates are files, documents, research_papers,
code_repository, and customer_support. You can also inspect or extend a
template programmatically:
from localvectordb import get_common_metadata_schemas
from localvectordb.core import MetadataField, MetadataFieldType
schema = dict(get_common_metadata_schemas("documents")) # a copy to extend
schema["language"] = MetadataField(type=MetadataFieldType.TEXT, indexed=True)
db = VectorDB("docs", "./storage", metadata_schema=schema)
Calling get_common_metadata_schemas() with no argument returns a dict of all
templates; an unknown name raises KeyError.
Supported Operators
Comparison Operators
Operator |
Description |
|---|---|
|
Equal to (default for simple values) |
|
Not equal to |
|
Greater than |
|
Less than |
|
Greater than or equal to |
|
Less than or equal to |
|
Value in list |
|
Value not in list |
String Operators
Operator |
Description |
|---|---|
|
SQL |
|
Case-insensitive |
|
Contains substring |
|
Starts with substring |
|
Ends with substring |
Existence Operators
Operator |
Description |
|---|---|
|
Field exists and is not null |
|
Field does not exist or is null |
Type Operators
Operator |
Description |
|---|---|
|
Check field type: |
Logical Operators
Operator |
Description |
|---|---|
|
All conditions must be true |
|
At least one condition must be true |
|
Condition must be false |
JSON Operators
For metadata fields with JSON type:
Operator |
Description |
|---|---|
|
JSON array contains value |
|
JSON array does not contain value |
Basic Usage Examples
Simple Equality
Filter documents with exact field matches:
# Find documents by a specific author
docs = db.filter(where={"author": "John Doe"})
# Find published documents by John Doe from 2023
docs = db.filter(where={
"author": "John Doe",
"year": 2023,
"published": True
})
Range Queries
Filter with numeric or date ranges:
# Find documents between 2020-2024 (inclusive) with a rating > 4.0
docs = db.filter(where={
"year": {"$gte": 2020, "$lte": 2024},
"rating": {"$gt": 4.0}
})
# Find documents created in 2024 but updated before December 31st
docs = db.filter(where={
"created_at": {"$gte": "2024-01-01"},
"updated_at": {"$lt": "2024-12-31"}
})
String Operations
Search and match text content:
# Find documents with "python" in title, authors starting with "Dr.", and case-insensitive machine learning in description
docs = db.filter(where={
"title": {"$contains": "python"},
"author": {"$startswith": "Dr."},
"description": {"$ilike": "%machine learning%"}
})
# Find documents with company emails and tutorial categories
docs = db.filter(where={
"email": {"$like": "%@company.com"},
"category": {"$endswith": "_tutorial"}
})
List Operations
Work with lists and arrays:
# Find documents in tech, science, or education categories, excluding drafts and archived documents
docs = db.filter(where={
"category": {"$in": ["tech", "science", "education"]},
"status": {"$nin": ["draft", "archived"]}
})
# Find documents with "python" in tags array but without "deprecated" in keywords
docs = db.filter(where={
"tags": {"$contains": "python"}, # JSON array contains "python"
"keywords": {"$not_contains": "deprecated"}
})
Advanced Usage Examples
Logical Operations
Combine multiple conditions with logical operators:
# Find tech documents from 2020+ with rating >= 4.0 (explicit AND)
docs = db.filter(where={
"$and": [
{"year": {"$gte": 2020}},
{"rating": {"$gte": 4.0}},
{"category": "tech"}
]
})
# Find documents by John Doe, Jane Smith, or in the featured category
docs = db.filter(where={
"$or": [
{"author": "John Doe"},
{"author": "Jane Smith"},
{"category": "featured"}
]
})
# Find recent tech documents (by category OR programming tags) that are NOT archived
docs = db.filter(where={
"$and": [
{"year": {"$gte": 2020}},
{"$or": [
{"category": "tech"},
{"tags": {"$contains": "programming"}}
]},
{"$not": {"status": "archived"}}
]
})
Existence and Type Checking
Validate field presence and types:
# Find documents missing optional fields but having required fields
docs = db.filter(where={
"optional_field": {"$exists": False},
"required_field": {"$exists": True}
})
# Find documents with specific data types (numeric ratings, array tags, object metadata, string descriptions)
docs = db.filter(where={
"rating": {"$type": "number"},
"tags": {"$type": "array"},
"metadata": {"$type": "object"},
"description": {"$type": "string"}
})
Ordering and Pagination
Sort and paginate filtered results:
# Find tech documents, order by newest first, get page 3 (items 21-30)
docs = db.filter(
where={"category": "tech"},
order_by="created_at DESC",
limit=10,
offset=20
)
# Find recent documents with highest ratings first, limit to 50 results
docs = db.filter(
where={"year": {"$gte": 2020}},
order_by="rating DESC",
limit=50
)
API Usage Examples
Local Database (LocalVectorDB)
Direct usage with the local database:
from localvectordb import LocalVectorDB
# Initialize database
db = LocalVectorDB("my_database")
# Find recent documents by John Doe or Jane Smith from 2020 onwards
docs = db.filter(where={
"author": {"$in": ["John Doe", "Jane Smith"]},
"year": {"$gte": 2020}
})
# Find recent research documents: approved peer-reviewed papers OR highly cited papers, newest first
docs = db.filter(
where={
"$and": [
{"category": "research"},
{"$or": [
{"peer_reviewed": True},
{"citation_count": {"$gte": 100}}
]}
]
},
order_by="publication_date DESC",
limit=25
)
Remote Database (RemoteVectorDB)
Client usage for remote databases:
from localvectordb.client import RemoteVectorDB
# Connect to remote database
db = RemoteVectorDB(
"my_database",
"http://localhost:8000",
api_key="your_api_key"
)
# Find high-quality tech documents in English or Spanish
docs = db.filter(where={
"$and": [
{"category": "tech"},
{"rating": {"$gte": 4.0}},
{"language": {"$in": ["en", "es"]}}
]
})
REST API Usage
HTTP API examples using curl:
Simple Filtering
Find documents by John Doe from 2020 onwards:
curl -X POST "http://localhost:8000/api/v1/databases/my_database/filter" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_api_key" \
-d '{
"where": {
"author": "John Doe",
"year": {"$gte": 2020}
}
}'
Complex Filtering with Pagination
Find high-quality tech/science documents that are featured OR trending, newest first:
curl -X POST "http://localhost:8000/api/v1/databases/my_database/filter" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_api_key" \
-d '{
"where": {
"$and": [
{"category": {"$in": ["tech", "science"]}},
{"rating": {"$gte": 4.0}},
{"$or": [
{"featured": true},
{"trending": true}
]}
]
},
"order_by": "created_at DESC",
"limit": 10,
"offset": 0
}'
String Search Operations
Find machine learning articles by doctors with AI in the description:
curl -X POST "http://localhost:8000/api/v1/databases/my_database/filter" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_api_key" \
-d '{
"where": {
"title": {"$contains": "machine learning"},
"author": {"$startswith": "Dr."},
"description": {"$ilike": "%artificial intelligence%"}
},
"limit": 20
}'
JSON Array Operations
Find Python documents without deprecated content, with specific skill requirements:
curl -X POST "http://localhost:8000/api/v1/databases/my_database/filter" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_api_key" \
-d '{
"where": {
"tags": {"$contains": "python"},
"categories": {"$not_contains": "deprecated"},
"skills_required": {"$in": [["python"], ["javascript"], ["python", "sql"]]}
}
}'
Search Integration
Enhanced filtering works seamlessly with search operations:
Vector Search with Filtering
# Search for machine learning tutorials: recent, tech/education category, intermediate difficulty or below
results = db.query(
"machine learning tutorial",
search_type="vector",
filters={
"year": {"$gte": 2020},
"category": {"$in": ["tech", "education"]},
"difficulty": {"$lte": "intermediate"}
}
)
Hybrid Search with Complex Filtering
# Search for Python programming content: English language, beginner-friendly OR tutorial content, high quality
results = db.query(
"python programming",
search_type="hybrid",
filters={
"$and": [
{"language": "en"},
{"$or": [
{"level": "beginner"},
{"tags": {"$contains": "tutorial"}}
]},
{"rating": {"$gte": 4.0}}
]
},
vector_weight=0.5
)
Search API with Filtering
Search for recent NLP content in AI category OR with NLP tags:
curl -X POST "http://localhost:8000/api/v1/databases/my_database/query" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_api_key" \
-d '{
"query": "natural language processing",
"search_type": "hybrid",
"filters": {
"$and": [
{"year": {"$gte": 2020}},
{"$or": [
{"category": "ai"},
{"tags": {"$contains": "nlp"}}
]}
]
},
"k": 10
}'
Performance and Best Practices
Indexing Strategy
Create indexes on frequently filtered fields:
from localvectordb.core import MetadataField, MetadataFieldType
# Define schema with indexed fields and optional embeddings
metadata_schema = {
"author": MetadataField(type=MetadataFieldType.TEXT, indexed=True),
"title": MetadataField(type=MetadataFieldType.TEXT, indexed=True,
embedding_enabled=True, # Enable vector search on title
fts_enabled=True), # Enable full-text search
"abstract": MetadataField(type=MetadataFieldType.TEXT,
embedding_enabled=True), # Enable embeddings without indexing
"year": MetadataField(type=MetadataFieldType.INTEGER, indexed=True),
"category": MetadataField(type=MetadataFieldType.TEXT, indexed=True),
"rating": MetadataField(type=MetadataFieldType.REAL, indexed=True),
"tags": MetadataField(type=MetadataFieldType.JSON, indexed=False) # JSON operations are slower
}
Query Optimization Tips
Use indexed fields for frequently filtered columns
Combine simple conditions before using logical operators
Place selective filters first in
$andoperationsUse appropriate operators for data types
Limit result sets with
limitparameter
# Good: Place selective filter first, then broader filter
# Find documents by a specific author (selective), then filter by broader categories
docs = db.filter(where={
"$and": [
{"author": "Specific Author"}, # Very selective
{"category": {"$in": ["tech", "science"]}} # Less selective
]
})
# Good: Use appropriate operators for data types
# Find high-rated AI documents with boolean exact match
docs = db.filter(where={
"rating": {"$gte": 4.0}, # Numeric comparison
"title": {"$contains": "AI"}, # String search
"published": True # Boolean exact match
})
Performance Considerations
Note
JSON Operations: $contains and $not_contains on JSON fields may be slower on large datasets. Consider restructuring data if these operations are frequent.
Tip
Complex Queries: Test complex logical operations with small datasets first to understand performance characteristics.
Error Handling
The filtering system provides clear error messages for common issues:
Invalid Field Names
try:
docs = db.filter(where={"invalid_field": "value"})
except DatabaseError as e:
print(f"Filter error: {e}")
# Error: Field 'invalid_field' not found in metadata schema
Unsupported Operators
try:
docs = db.filter(where={"author": {"$invalid": "value"}})
except DatabaseError as e:
print(f"Filter error: {e}")
# Error: Unsupported operator: $invalid
Operator/Type Mismatches
Using a string operator such as $contains against a non-text field does not
raise; it falls back to a substring LIKE match on the value’s text form,
which is rarely what you want. Prefer the numeric comparison operators for
numeric fields:
# Silently does a LIKE '%2020%' match — usually not intended:
docs = db.filter(where={"year": {"$contains": "2020"}})
# Use a numeric comparison instead:
docs = db.filter(where={"year": 2020})
docs = db.filter(where={"year": {"$gte": 2020, "$lt": 2025}})
Common Error Messages
Error Type |
Description |
|---|---|
|
Field doesn’t exist in the database schema |
|
Operator not recognized or not supported |
|
Field name contains invalid characters |
|
Wrong value type for operator (e.g., |
|
Attempting JSON operations on non-JSON field |
Complete Examples
Research Paper Database
from localvectordb import LocalVectorDB
from localvectordb.core import MetadataField, MetadataFieldType
# Create database with research paper schema
metadata_schema = {
"title": MetadataField(type=MetadataFieldType.TEXT, indexed=True),
"authors": MetadataField(type=MetadataFieldType.JSON),
"year": MetadataField(type=MetadataFieldType.INTEGER, indexed=True),
"journal": MetadataField(type=MetadataFieldType.TEXT, indexed=True),
"citations": MetadataField(type=MetadataFieldType.INTEGER, indexed=True),
"keywords": MetadataField(type=MetadataFieldType.JSON),
"peer_reviewed": MetadataField(type=MetadataFieldType.BOOLEAN, indexed=True)
}
db = LocalVectorDB("research_papers", metadata_schema=metadata_schema)
# Find highly cited machine learning papers from top journals (100+ citations, recent, peer-reviewed)
papers = db.filter(where={
"$and": [
{"keywords": {"$contains": "machine learning"}},
{"citations": {"$gte": 100}},
{"journal": {"$in": ["Nature", "Science", "ICML", "NeurIPS"]}},
{"year": {"$gte": 2020}},
{"peer_reviewed": True}
]
}, order_by="citations DESC", limit=20)
E-commerce Product Database
# Find affordable electronics from premium brands OR with wireless features, in stock, not discontinued
product_filters = {
"$and": [
{"category": {"$in": ["electronics", "computers"]}},
{"price": {"$gte": 100, "$lte": 1000}},
{"rating": {"$gte": 4.0}},
{"in_stock": True},
{"$or": [
{"brand": {"$in": ["Apple", "Samsung", "Sony"]}},
{"features": {"$contains": "wireless"}}
]},
{"$not": {"discontinued": True}}
]
}
products = db.filter(
where=product_filters,
order_by="rating DESC",
limit=50
)
Document Management System
# Find recent approved documents by key authors/departments OR urgent items, excluding confidential drafts
documents = db.filter(where={
"$and": [
{"status": "approved"},
{"created_at": {"$gte": "2024-01-01"}},
{"$or": [
{"author": {"$in": ["John Doe", "Jane Smith"]}},
{"department": {"$in": ["engineering", "research"]}},
{"tags": {"$contains": "urgent"}}
]},
{"document_type": {"$nin": ["draft", "template"]}},
{"confidential": {"$ne": True}}
]
}, order_by="created_at DESC")