department=legal, region=us, status=published, or author=alice.
HydraDB has two metadata layers:
If a field will be scoped on every query, it belongs in
metadata and the database schema. If it’s ad-hoc or unique to one document, use additional_metadata instead.
1. Choose the right metadata layer
The
database field was formerly tenant_id and collection was formerly sub_tenant_id; the old names still work as deprecated aliases. Follow this for when to use database and collection.
2. How metadata filters run
For user-providedmetadata_filters, HydraDB uses a correctness-first pipeline:
- MongoDB source-id prefilter. Safe scalar tenant/additional metadata filters are resolved to matching
source_ids in MongoDB. - Scoped retrieval. Vector/BM25 retrieval searches only those source IDs.
- Post-filter correctness net. Hydrated chunks are checked again against the requested metadata. This also protects graph expansion and fallback/retry paths from leaking excluded sources.
Filter semantics
3. Define tenant metadata schema
Most of the time the defaults are right. When they aren’t, here’s where to start:- Plan scoping fields before first ingest. Schema is immutable, and undeclared scope keys are silently ignored at query time. If you’ll scope on it more than once, declare it.
- Pick
metadatafor hot paths,additional_metadatafor cold ones. Database-level scopes are pre-applied in the vector store; document-level scopes force a post-retrieval pass with over-fetch. - Use exact-equality only.
metadata_filtersare equality constraints across all categories. Range, contains, or fuzzy matching belong in the query, query mode, or downstream reranking - not here. - Keep keys stable. Renaming a metadata key requires re-ingesting affected sources. Same goes for changing
enable_matchflags. - Ingested metadata is immutable. Once a source is indexed, its
metadataandadditional_metadatavalues are locked. To change them, re-ingest the source with the new values (useupsert: trueand the sameid). - Don’t substitute
metadata_filtersforcollection.metadata_filtersscopes results inside a partition. For partitioning by user, team, or workspace, usecollection.
4. Minimal working example
Two phases: set up metadata (declare the schema, then attach values at ingest), then scope at query.Step 1 - Create metadata
The schema lives at the database level; values land on each source at ingest time. Both happen before any query.Step 1a: Declare the schema at database creation
Schema field options
Limits and guardrails:
- Up to 32 custom tenant metadata fields.
- Field names are unique case-insensitively.
- Dense/sparse embedding flags are only valid on
VARCHARfields. - Runtime
metadatavalues must match the declared type when the tenant has a schema. - Unknown
metadatakeys are rejected on ingest/edit when a non-empty tenant schema exists.
Add schema fields later
You can add database metadata fields after database creation withPATCH /databases/{database}/metadata-schema. This is additive only:
- add new fields: yes
- delete fields: no
- change type/flags of existing fields: no
5. Attach metadata at ingest
For knowledge ingestion, sendmetadata and additional_metadata on each document_metadata[] item or app_knowledge[] item.
6. Query with metadata filters
Mix database-level (top-level) and document-level (nested) scopes in the samemetadata_filters object:
additional_metadata wins on conflicts.
7. Update metadata without re-ingesting
UsePATCH /context/sources/{source_id}/metadata when you know the source ID and need to update metadata in place.
- The source must already exist.
collectionis required.- At least one of
tenant_metadataoradditional_metadatais required. - The update is a merge/upsert: sent keys are inserted or overwritten; omitted keys are preserved.
document_metadatais not accepted on this endpoint; useadditional_metadata.enable_match-only tenant metadata updates are MongoDB-only and take effect for filters/listing.- If an edited tenant metadata field has
enable_dense_embeddingorenable_sparse_embedding, HydraDB synchronously syncs the relevant vector store lane and reportsvector_sync_required/vector_syncedin the response (themilvus_sync_required/milvus_syncedaliases are still emitted, deprecated).
upsert: true and the same source id. Upsert replaces the source payload and metadata supplied by ingestion.
8. Listing with metadata filters
UsePOST /context/list when you want to browse or page sources rather than run semantic retrieval:
/context/list also accepts legacy aliases tenant_metadata for metadata and document_metadata for additional_metadata.
9. Common mistakes
10. Advanced patterns
Stacked scopes with collection partitioning. Usecollection for the partition (per-user, per-workspace), and use metadata_filters to scope inside that partition. They’re complementary, not interchangeable. See Multi-Tenant.
Published vs draft. Add a status field with enable_match: true to your schema; tag every source with metadata.status = "draft" | "published"; pass metadata_filters: { status: "published" } on user-facing queries. Keeps work-in-progress out of customer answers automatically.
Multi-language corpora. Add a language field with enable_match: true; route each query to the right language by passing metadata_filters: { language: detect_language(query) }.
Schema-as-product. Treat database_metadata_schema as part of your data contract - review it like a database migration. The cost of getting it wrong (immutability + re-ingest) is real; the cost of getting it right is one extra meeting.
Related
- Knowledge - what attaches to knowledge sources
- Memories - metadata fields on memory items
- Multi-Tenant Support - partitioning vs scoping
- Query - how
metadata_filtersinteract with ranking - Create Database - API Reference - full
database_metadata_schemareference - Query - API Reference - full
metadata_filtersreference - List Context - source browsing filters
- Update Source Metadata - point metadata edits
- Update Metadata Schema - additive database schema changes