docs/mintlify/cloud/search-api/search-basics.mdx
import { Callout } from '/snippets/callout.mdx';
This page covers the basics of Search construction. For detailed usage of specific components, see:
K() and .where()Knn and .rank() for vector search.select() and pagination with .limit()search = Search()
search = Search( where={"status": "active"}, rank={"$knn": {"query": [0.1, 0.2]}}, limit=10, select=["#document", "#score"] )
```typescript TypeScript
import { Search } from 'chromadb';
// Create an empty search
const search = new Search();
// Direct construction with parameters
const search2 = new Search({
where: { status: "active" },
rank: { $knn: { query: [0.1, 0.2] } },
limit: 10,
select: ["#document", "#score"]
});
use chroma::types::{Key, QueryVector, RankExpr, SearchPayload};
let search = SearchPayload::default()
.r#where(Key::field("status").eq("active"))
.rank(RankExpr::Knn {
query: QueryVector::Dense(vec![0.1, 0.2]),
key: Key::Embedding,
limit: 10,
default: None,
return_rank: false,
})
.limit(Some(10), 0)
.select([Key::Document, Key::Score]);
The Search class accepts four optional parameters:
where: Filter expressions to narrow down results
Where expression, dict, or NoneNone (no filtering)rank: Ranking expressions to score and order results
Rank expression, dict, or NoneNone (no ranking, natural order)limit: Pagination control
Limit object, dict, int, or NoneNone (no limit)select: Fields to include in results
Select object, dict, list, set, or NoneNone (returns IDs only)#id, #document, #embedding, #metadata, #score, or any custom metadata fieldThe Search class provides a fluent interface with method chaining. Each method returns a new Search instance, making queries immutable and safe to reuse.
For detailed usage of each builder method, see the respective sections:
.where() - See Filter expressions.rank() - See Ranking and scoring.limit() - See Pagination.select() and .select_all() - See Field selectionsearch = (Search() .where(K("status") == "published") .rank(Knn(query="machine learning applications")) .limit(10) .select(K.DOCUMENT, K.SCORE))
base_search = Search().where(K("category") == "science") search_v1 = base_search.limit(5) # New instance search_v2 = base_search.limit(10) # Different instance
search = Search() search = search.where(K("status") == "active") search = search.rank(Knn(query="recent advances in quantum computing")) search = search.limit(20) search = search.select(K.DOCUMENT, K.METADATA)
```typescript TypeScript
import { Search, K, Knn } from 'chromadb';
// Basic method chaining
const search = new Search()
.where(K("status").eq("published"))
.rank(Knn({ query: "machine learning applications" }))
.limit(10)
.select(K.DOCUMENT, K.SCORE);
// Each method returns a new instance
const baseSearch = new Search().where(K("category").eq("science"));
const searchV1 = baseSearch.limit(5); // New instance
const searchV2 = baseSearch.limit(10); // Different instance
// Progressive building
let search2 = new Search();
search2 = search2.where(K("status").eq("active"));
search2 = search2.rank(Knn({ query: "recent advances in quantum computing" }));
search2 = search2.limit(20);
search2 = search2.select(K.DOCUMENT, K.METADATA);
use chroma::types::{Key, QueryVector, RankExpr, SearchPayload};
let base = SearchPayload::default().r#where(Key::field("category").eq("science"));
let search_v1 = base.clone().limit(Some(5), 0);
let search_v2 = base.clone().limit(Some(10), 0);
let search = SearchPayload::default()
.r#where(Key::field("status").eq("active"))
.rank(RankExpr::Knn {
query: QueryVector::Dense(vec![0.2, 0.4, 0.6]),
key: Key::Embedding,
limit: 20,
default: None,
return_rank: false,
})
.limit(Some(20), 0)
.select([Key::Document, Key::Metadata]);
Benefits of immutability:
You can create Search objects directly with various parameter types:
<CodeGroup> ```python Python from chromadb import Search, K, Knn from chromadb.execution.expression.operator import Limit, Selectsearch = Search( where=K("status") == "active", rank=Knn(query="latest research papers"), limit=Limit(limit=10, offset=0), select=Select(keys={K.DOCUMENT, K.SCORE}) )
search = Search( where=K("category") == "science", # Expression rank={"$knn": {"query": "quantum mechanics"}}, # Dictionary limit=10, # Integer select=[K.DOCUMENT, K.SCORE, "author"] # List )
search = Search()
search = Search(where=K("status") == "published")
search = Search(rank=Knn(query="artificial intelligence"))
```typescript TypeScript
import { Search, K, Knn } from 'chromadb';
// With expression objects
const search1 = new Search({
where: K("status").eq("active"),
rank: Knn({ query: "latest research papers" }),
limit: { limit: 10, offset: 0 },
select: [K.DOCUMENT, K.SCORE]
});
// With dictionaries (MongoDB-style)
const search2 = new Search({
where: { status: "active" },
rank: { $knn: { query: "latest research papers" } },
limit: { limit: 10, offset: 0 },
select: { keys: ["#document", "#score"] }
});
// Mixed types
const search3 = new Search({
where: K("category").eq("science"), // Expression
rank: { $knn: { query: "quantum mechanics" } }, // Dictionary
limit: 10, // Number
select: [K.DOCUMENT, K.SCORE, "author"] // Array
});
// Minimal search (IDs only)
const search4 = new Search();
// Just filtering
const search5 = new Search({ where: K("status").eq("published") });
// Just ranking
const search6 = new Search({ rank: Knn({ query: "artificial intelligence" }) });
use chroma::types::{Key, QueryVector, RankExpr, SearchPayload};
let search = SearchPayload::default()
.r#where(Key::field("category").eq("science"))
.rank(RankExpr::Knn {
query: QueryVector::Dense(vec![0.1, 0.2, 0.3]),
key: Key::Embedding,
limit: 10,
default: None,
return_rank: false,
})
.limit(Some(10), 0)
.select([Key::Document, Key::Score, Key::field("author")]);
An empty Search object has specific default behaviors:
<CodeGroup> ```python Python # Empty search search = Search()result = collection.search(search)
search = Search().select(K.DOCUMENT, K.METADATA) result = collection.search(search)
```typescript TypeScript
// Empty search
const search = new Search();
// Equivalent to:
// - where: undefined (returns all documents)
// - rank: undefined (natural storage order)
// - limit: undefined (no limit on results)
// - select: empty (returns IDs only)
const result = await collection.search(search);
// Result contains only IDs, no documents/embeddings/metadata/scores
// Add selection to get more fields
const search2 = new Search().select(K.DOCUMENT, K.METADATA);
const result2 = await collection.search(search2);
// Now includes documents and metadata
Here are common patterns for building Search queries:
<CodeGroup> ```python Python from chromadb import Search, K, Knndef get_documents(): return Search().select(K.DOCUMENT, K.METADATA)
def filter_recent_science(): return (Search() .where((K("category") == "science") & (K("year") >= 2023)) .limit(10) .select(K.DOCUMENT, K.METADATA))
def search_similar(query): return (Search() .rank(Knn(query=query)) .limit(10) .select(K.DOCUMENT, K.SCORE))
def search_recent_science(query): return (Search() .where((K("category") == "science") & (K("year") >= 2023)) .rank(Knn(query=query)) .limit(10) .select(K.DOCUMENT, K.SCORE))
```typescript TypeScript
import { Search, K, Knn } from 'chromadb';
// Pattern 1: Baseline - no filter, no rank (natural storage order)
function getDocuments() {
return new Search().select(K.DOCUMENT, K.METADATA);
}
// Pattern 2: Filter only - no ranking
function filterRecentScience() {
return new Search()
.where(K("category").eq("science").and(K("year").gte(2023)))
.limit(10)
.select(K.DOCUMENT, K.METADATA);
}
// Pattern 3: Rank only - no filtering
function searchSimilar(query: string) {
return new Search()
.rank(Knn({ query: query }))
.limit(10)
.select(K.DOCUMENT, K.SCORE);
}
// Pattern 4: Both filter and rank
function searchRecentScience(query: string) {
return new Search()
.where(K("category").eq("science").and(K("year").gte(2023)))
.rank(Knn({ query: query }))
.limit(10)
.select(K.DOCUMENT, K.SCORE);
}