Skip to content
API Reference Zilliz Cloud Milvus Attu

Data Operations - Query & Search

This guide covers querying and searching data in Milvus collections.

Query retrieves entities based on filter expressions.

Query entities with a filter expression:

const results = await client.query({
collection_name: 'my_collection',
expr: 'age > 25',
output_fields: ['id', 'vector', 'text'],
});

Query specific entities by their IDs:

const results = await client.query({
collection_name: 'my_collection',
ids: [1, 2, 3, 4, 5],
output_fields: ['id', 'vector', 'text'],
});
const results = await client.query({
collection_name: 'my_collection',
expr: 'age > 25',
output_fields: ['id', 'text', 'price'],
limit: 10,
offset: 0,
order_by_fields: [{ field: 'price', order: 'desc' }],
});

order_by_fields can be a string, an array of strings, or an array of { field, order } objects:

await client.query({
collection_name: 'my_collection',
expr: 'age > 25',
output_fields: ['id', 'price', 'rating'],
order_by_fields: 'price:asc,rating:desc',
});
await client.query({
collection_name: 'my_collection',
expr: 'age > 25',
output_fields: ['id', 'price', 'rating'],
order_by: ['price:asc', { field: 'rating', order: 'desc' }], // alias
});
const results = await client.query({
collection_name: 'my_collection',
expr: 'age > 25',
partition_names: ['partition_1', 'partition_2'],
output_fields: ['id', 'text'],
});

Iterate through large result sets:

const iterator = await client.queryIterator({
collection_name: 'my_collection',
expr: 'age > 25',
output_fields: ['id', 'text'],
batch_size: 100,
});
while (true) {
const batch = await iterator.next();
if (batch.done) break;
console.log('Batch:', batch.value);
}

Get entities by IDs (simpler than query):

const results = await client.get({
collection_name: 'my_collection',
ids: [1, 2, 3],
output_fields: ['id', 'vector', 'text'],
});

Count entities matching a filter:

const result = await client.count({
collection_name: 'my_collection',
expr: 'age > 25',
});
console.log('Count:', result.data);

Search finds similar vectors using distance metrics.

const results = await client.search({
collection_name: 'my_collection',
data: [[0.1, 0.2, 0.3, 0.4]], // Search vector
limit: 10,
output_fields: ['id', 'text'],
});

perform a vector similarity search using the vectors associated with exact entity IDs:

const results = await client.search({
collection_name: 'my_collection',
ids: [1, 2, 3], // primary keys
limit: 10,
output_fields: ['id', 'text'],
});

[!NOTE]

  • When ids are provided, the data parameter (dummy vectors) is not required.
  • The provided ids must match the collection’s Primary Key type (Int64 or VarChar).
  • For collections with multiple vector fields, explicitly specifying anns_field is recommended (and required to disambiguate).
const results = await client.search({
collection_name: 'my_collection',
data: [
[0.1, 0.2, 0.3, 0.4],
[0.5, 0.6, 0.7, 0.8],
],
limit: 10,
output_fields: ['id', 'text'],
});

Combine vector search with scalar filters:

const results = await client.search({
collection_name: 'my_collection',
data: [[0.1, 0.2, 0.3, 0.4]],
expr: 'age > 25 AND category == "tech"',
limit: 10,
output_fields: ['id', 'text', 'age'],
});

Sort search results by scalar fields after vector retrieval:

const results = await client.search({
collection_name: 'my_collection',
data: [[0.1, 0.2, 0.3, 0.4]],
limit: 10,
output_fields: ['id', 'price', 'rating'],
order_by_fields: [
{ field: 'price', order: 'asc' },
{ field: 'rating', order: 'desc' },
],
});

You can also pass order_by_fields as a string, for example 'price:asc,rating:desc'. If you also pass params.order_by_fields, the top-level order_by_fields value takes precedence.

Configure search parameters for different index types:

// For IVF indexes
const results = await client.search({
collection_name: 'my_collection',
data: [[0.1, 0.2, 0.3, 0.4]],
params: {
nprobe: 64, // Number of clusters to search
},
limit: 10,
});
// For HNSW indexes
const results = await client.search({
collection_name: 'my_collection',
data: [[0.1, 0.2, 0.3, 0.4]],
params: {
ef: 100, // Search width
},
limit: 10,
});
const results = await client.search({
collection_name: 'my_collection',
data: [[0.1, 0.2, 0.3, 0.4]],
partition_names: ['partition_1'],
limit: 10,
});

Iterate through large search results:

const iterator = await client.searchIterator({
collection_name: 'my_collection',
data: [[0.1, 0.2, 0.3, 0.4]],
expr: 'age > 25',
limit: 1000,
batch_size: 100,
});
while (true) {
const batch = await iterator.next();
if (batch.done) break;
console.log('Batch:', batch.value);
}

Search with multiple vector fields:

const results = await client.hybridSearch({
collection_name: 'my_collection',
reqs: [
{
data: [[0.1, 0.2, 0.3, 0.4]],
anns_field: 'text_vector',
param: { nprobe: 64 },
limit: 10,
},
{
data: [[0.5, 0.6, 0.7, 0.8]],
anns_field: 'image_vector',
param: { nprobe: 64 },
limit: 10,
},
],
ranker: 'rrf', // Reciprocal Rank Fusion
limit: 10,
output_fields: ['id', 'text'],
});

Filter expressions use Milvus expression syntax:

'age > 25';
'age >= 25';
'age < 25';
'age <= 25';
'age == 25';
'age != 25';
'age > 25 AND category == "tech"';
'age > 25 OR age < 18';
'NOT (age > 25)';
'id in [1, 2, 3, 4, 5]';
'category in ["tech", "science"]';
'text like "milvus%"';
'text like "%database%"';
'metadata.category == "tech"';
'metadata.tags[0] == "ai"';

Search results include:

const results = await client.search({
collection_name: 'my_collection',
data: [[0.1, 0.2, 0.3, 0.4]],
limit: 10,
});
results.results.forEach((result) => {
console.log('ID:', result.id);
console.log('Distance:', result.distance);
console.log('Score:', result.score);
console.log('Entity:', result.entity);
});

For element-level retrieval, Milvus can return the matching element offsets for array or multi-vector fields. The SDK flattens element_indices into result rows and adds an offset property that identifies the matched element within the source field.

const results = await client.search({
collection_name: 'chunked_docs',
data: [
[
/* query vector */
],
],
anns_field: 'chunk_embeddings',
limit: 10,
output_fields: ['doc_id', 'title'],
});
results.results.forEach((row) => {
console.log('Document:', row.doc_id);
console.log('Matched element offset:', row.offset);
});

Grouped search responses can also include group_by_field_values, which the SDK exposes on each result row:

results.results.forEach((row) => {
console.log('Score:', row.score);
console.log('Group by values:', row.group_by_field_values);
});

Specify which fields to return:

// Return specific fields
output_fields: ['id', 'text', 'age'];
// Return all fields
output_fields: ['*'];
// Return vector fields
output_fields: ['id', 'vector'];

IVF indexes:

  • nprobe: Higher values improve recall but slower (typical: 16-256)

HNSW indexes:

  • ef: Higher values improve recall but slower (typical: 50-200)

Search multiple vectors efficiently:

const results = await client.search({
collection_name: 'my_collection',
data: [
[
/* vector 1 */
],
[
/* vector 2 */
],
[
/* vector 3 */
],
],
limit: 10,
});

Load collections before searching:

await client.loadCollectionSync({
collection_name: 'my_collection',
});
// Now search
const results = await client.search({
/* ... */
});
  1. Use appropriate limits: Set reasonable limits to avoid large result sets
  2. Filter before search: Use filter expressions to narrow down results
  3. Tune search parameters: Adjust nprobe/ef based on your recall/performance needs
  4. Use iterators: For large result sets, use query/search iterators
  5. Load collections: Always load collections before searching
  6. Batch operations: Search multiple vectors in one call when possible
import { MilvusClient, DataType } from '@zilliz/milvus2-sdk-node';
const client = new MilvusClient({
address: 'localhost:19530',
});
await client.connectPromise;
// Load collection
await client.loadCollectionSync({
collection_name: 'my_collection',
});
// Query
const queryResults = await client.query({
collection_name: 'my_collection',
expr: 'age > 25',
output_fields: ['id', 'text', 'age'],
limit: 10,
});
console.log('Query results:', queryResults.data);
// Search
const searchResults = await client.search({
collection_name: 'my_collection',
data: [Array.from({ length: 128 }, () => Math.random())],
expr: 'age > 25',
limit: 10,
output_fields: ['id', 'text'],
params: {
nprobe: 64,
},
});
console.log('Search results:', searchResults.results);