Skip to main content

Node.js Client Examples

Comprehensive examples for the hlquery Node.js client library.

Example Files

The Node.js client includes several example files demonstrating different aspects of the API:

  • basic_usage.js - Basic client initialization and simple operations
  • collections.js - Collection management operations
  • documents.js - Document CRUD operations
  • search.js - Various search patterns and options
  • vector.js - Vector search capabilities with multiple collections

Running Examples

Main Example File

The main example file (example.js) provides a comprehensive demonstration of all API features:

# Run all examples (default)
node example.js

# Run specific command
node example.js cols # List collections
node example.js docs my_collection # List documents in collection
node example.js status # Show server health and status
node example.js help # Show help message

Individual Example Files

# Basic usage
node examples/basic_usage.js

# Collections
node examples/collections.js

# Documents
node examples/documents.js

# Search
node examples/search.js

# Vector search
node examples/vector.js

Example Output

Running node examples/basic_usage.js against a local server can look like this:

Health Status: 200
Health Body: {
auth_enabled: false,
auth_required: false,
demo_mode: false,
engine: 'epoll',
health_degraded: false,
loaded_modules: [ 'test', 'banned', 'lang', 'analytics' ],
readonly_mode: false,
server: 'hlquery',
socket_engine: 'epoll',
status: 'ok',
version: '1.0'
}
Found 0 collections

That means the Node.js client returns a Response object, and getBody() gives you the parsed JSON body you can inspect directly.

Table of Contents

Basic Operations

Initialize Client

const Client = require('./lib/Client');

// Basic initialization
const client = new Client('http://localhost:9200');

// With authentication
const client = new Client('http://localhost:9200', {
token: 'your_token_here',
auth_method: 'bearer'
});

// With timeout
const client = new Client('http://localhost:9200', {
timeout: 5000 // 5 seconds
});

Health Check

async function checkHealth() {
const health = await client.health();

if (health.isSuccess()) {
const body = health.getBody();
console.log('Server status:', body.status);
console.log('Engine:', body.engine);
console.log('Version:', body.version);
} else {
console.error('Health check failed:', health.getError());
}
}

Typical health.getBody() result:

{
auth_enabled: false,
auth_required: false,
demo_mode: false,
engine: 'epoll',
health_degraded: false,
loaded_modules: ['test', 'banned', 'lang', 'analytics'],
readonly_mode: false,
server: 'hlquery',
socket_engine: 'epoll',
status: 'ok',
version: '1.0'
}

Server Statistics

async function getStats() {
const stats = await client.stats();
const body = stats.getBody();

console.log('Collections:', body.collections?.total);
console.log('Documents:', body.documents?.total);
console.log('Memory:', body.memory);
console.log('Uptime:', body.uptime);
}

Typical response shape:

{
collections: {
total: 12
},
documents: {
total: 100100
},
memory: {
used: 12345678
},
uptime: 3456
}

The exact numbers depend on your running server state. The important part is the body shape returned by stats.getBody().

Collection Management

Create Collection

async function createProductCollection() {
const schema = {
fields: [
{ name: 'title', type: 'string' },
{ name: 'description', type: 'string' },
{ name: 'price', type: 'float' },
{ name: 'category', type: 'string' },
{ name: 'tags', type: 'string[]' },
{ name: 'in_stock', type: 'bool' },
{ name: 'rating', type: 'float' }
]
};

const result = await client.collections().create('products', schema);

if (result.isSuccess()) {
console.log('Collection created successfully');
} else {
console.error('Failed to create collection:', result.getError());
}
}

List Collections

async function listCollections() {
const result = await client.listCollections(0, 10);

if (result.isSuccess()) {
const body = result.getBody();
const collections = body.collections || [];

console.log(`Found ${collections.length} collections:`);
collections.forEach(col => {
console.log(`- ${col.name} (${col.num_documents} documents)`);
});
}
}

Get Collection Details

async function getCollectionInfo(collectionName) {
const result = await client.getCollection(collectionName);

if (result.isSuccess()) {
const body = result.getBody();
console.log('Collection:', body.name);
console.log('Fields:', body.fields);
console.log('Document count:', body.num_documents);
}
}

Update Collection Schema

async function addFieldToCollection(collectionName) {
const result = await client.getCollection(collectionName);

if (result.isSuccess()) {
const body = result.getBody();
const updatedSchema = {
fields: [
...body.fields,
{ name: 'new_field', type: 'string' }
]
};

const updateResult = await client.collections().update(collectionName, {
fields: updatedSchema.fields
});

if (updateResult.isSuccess()) {
console.log('Collection updated successfully');
}
}
}

Delete Collection

async function deleteCollection(collectionName) {
const result = await client.deleteCollection(collectionName);

if (result.isSuccess()) {
console.log('Collection deleted successfully');
} else {
console.error('Failed to delete collection:', result.getError());
}
}

Document Operations

Add Single Document

async function addProduct() {
const product = {
id: 'prod_001',
title: 'Wireless Headphones',
description: 'High-quality wireless headphones with noise cancellation',
price: 199.99,
category: 'electronics',
tags: ['audio', 'wireless', 'premium'],
in_stock: true,
rating: 4.5
};

const result = await client.documents().add('products', product);

if (result.isSuccess()) {
console.log('Product added:', result.getBody());
}
}

Update Document

async function updateProduct(productId) {
const updates = {
price: 179.99, // Price drop
in_stock: false
};

const result = await client.documents().update('products', productId, updates);

if (result.isSuccess()) {
console.log('Product updated successfully');
}
}

Get Document

async function getProduct(productId) {
const result = await client.getDocument('products', productId);

if (result.isSuccess()) {
const product = result.getBody();
console.log('Product:', product.title);
console.log('Price:', product.price);
console.log('In stock:', product.in_stock);
}
}

List Documents with Pagination

async function listProducts(page = 0, pageSize = 10) {
const offset = page * pageSize;
const result = await client.listDocuments('products', offset, pageSize);

if (result.isSuccess()) {
const body = result.getBody();
const documents = body.documents || [];

console.log(`Page ${page + 1} (${documents.length} products):`);
documents.forEach(doc => {
console.log(`- ${doc.title}: $${doc.price}`);
});
}
}

Bulk Import Documents

async function importProducts() {
const products = [
{
id: 'prod_001',
title: 'Laptop',
price: 999.99,
category: 'computers',
in_stock: true
},
{
id: 'prod_002',
title: 'Mouse',
price: 29.99,
category: 'accessories',
in_stock: true
},
{
id: 'prod_003',
title: 'Keyboard',
price: 79.99,
category: 'accessories',
in_stock: false
}
];

const result = await client.documents().import('products', products);

if (result.isSuccess()) {
const body = result.getBody();
console.log(`Imported ${body.num_imported} products`);
}
}

Delete Document

async function deleteProduct(productId) {
const result = await client.deleteDocument('products', productId);

if (result.isSuccess()) {
console.log('Product deleted successfully');
}
}

Search Examples

async function searchProducts(query) {
const result = await client.search('products', {
q: query,
query_by: 'title,description',
limit: 10
});

if (result.isSuccess()) {
const body = result.getBody();
const hits = body.hits || [];

console.log(`Found ${hits.length} results:`);
hits.forEach(hit => {
console.log(`- ${hit.document.title} (score: ${hit.text_match})`);
});
}
}

Search with Filters

async function searchWithFilters() {
const result = await client.search('products', {
q: 'laptop',
query_by: 'title',
filter_by: 'price:>500 && in_stock:true',
sort_by: 'price:asc',
limit: 20
});

if (result.isSuccess()) {
const body = result.getBody();
console.log(`Found ${body.found} products`);
}
}

Search with Facets

async function searchWithFacets() {
const result = await client.search('products', {
q: '*',
query_by: 'title',
facet_by: 'category,rating',
limit: 10
});

if (result.isSuccess()) {
const body = result.getBody();
const facets = body.facet_counts || [];

facets.forEach(facet => {
console.log(`\n${facet.field_name}:`);
facet.counts.forEach(count => {
console.log(` ${count.value}: ${count.count}`);
});
});
}
}
async function multiCollectionSearch() {
const searches = [
{ collection: 'products', q: 'laptop', query_by: 'title' },
{ collection: 'articles', q: 'laptop', query_by: 'content' },
{ collection: 'reviews', q: 'laptop', query_by: 'text' }
];

const result = await client.multiSearch(searches);

if (result.isSuccess()) {
const body = result.getBody();
const results = body.results || [];

results.forEach((searchResult, index) => {
console.log(`\nCollection: ${searches[index].collection}`);
console.log(`Found: ${searchResult.found} results`);
});
}
}
async function vectorSearch() {
// Assuming you have embeddings for your query
const queryVector = [0.1, 0.2, 0.3, 0.4, 0.5]; // Your embedding vector

const result = await client.vectorSearch('products', {
vector: queryVector,
limit: 10,
threshold: 0.7
});

if (result.isSuccess()) {
const body = result.getBody();
const hits = body.hits || [];

hits.forEach(hit => {
console.log(`- ${hit.document.title} (similarity: ${hit.vector_distance})`);
});
}
}

Advanced Features

Search with Highlighting

async function searchWithHighlighting(query) {
const result = await client.search('products', {
q: query,
query_by: 'title,description',
highlight_fields: 'title,description',
highlight_affix_num_tokens: 4,
limit: 10
});

if (result.isSuccess()) {
const body = result.getBody();
const hits = body.hits || [];

hits.forEach(hit => {
console.log(`Title: ${hit.highlights?.title || hit.document.title}`);
console.log(`Description: ${hit.highlights?.description || hit.document.description}`);
});
}
}

Search with Typo Tolerance

async function searchWithTypos(query) {
const result = await client.search('products', {
q: query,
query_by: 'title',
typo_tolerance: 'auto', // or 'off', 'min', 'max'
limit: 10
});

if (result.isSuccess()) {
const body = result.getBody();
console.log(`Found ${body.found} results (with typo tolerance)`);
}
}

Search with Synonyms

async function searchWithSynonyms(query) {
const result = await client.search('products', {
q: query,
query_by: 'title',
use_synonyms: true,
limit: 10
});

if (result.isSuccess()) {
const body = result.getBody();
console.log(`Found ${body.found} results (with synonyms)`);
}
}

Error Handling

Comprehensive Error Handling

const { HlqueryException, AuthenticationException, RequestException } = require('./lib/Exceptions');

async function safeOperation() {
try {
const result = await client.createCollection('test', schema);

if (result.isSuccess()) {
console.log('Operation successful');
} else {
console.error('Operation failed:', result.getError());
}
} catch (error) {
if (error instanceof AuthenticationException) {
console.error('Authentication failed. Check your token.');
} else if (error instanceof RequestException) {
console.error('Request failed:', error.message);
console.error('Status code:', error.statusCode);
} else if (error instanceof HlqueryException) {
console.error('hlquery error:', error.message);
} else {
console.error('Unexpected error:', error);
}
}
}

Real-World Scenarios

async function ecommerceSearch(userQuery, filters = {}) {
const searchParams = {
q: userQuery,
query_by: 'title,description,tags',
filter_by: buildFilterString(filters),
sort_by: filters.sortBy || 'text_match:desc',
facet_by: 'category,brand,price_range',
limit: 20
};

const result = await client.search('products', searchParams);

if (result.isSuccess()) {
const body = result.getBody();
return {
products: body.hits.map(hit => hit.document),
facets: body.facet_counts,
total: body.found
};
}

return null;
}

function buildFilterString(filters) {
const conditions = [];

if (filters.category) {
conditions.push(`category:${filters.category}`);
}

if (filters.minPrice) {
conditions.push(`price:>=${filters.minPrice}`);
}

if (filters.maxPrice) {
conditions.push(`price:<=${filters.maxPrice}`);
}

if (filters.inStock) {
conditions.push('in_stock:true');
}

return conditions.join(' && ');
}

Content Management System

async function cmsSearch(query, contentType = null) {
const searchParams = {
q: query,
query_by: 'title,content',
limit: 10
};

if (contentType) {
searchParams.filter_by = `type:${contentType}`;
}

const result = await client.search('content', searchParams);

if (result.isSuccess()) {
return result.getBody().hits.map(hit => ({
id: hit.document.id,
title: hit.document.title,
excerpt: hit.document.content.substring(0, 200),
score: hit.text_match
}));
}

return [];
}

Analytics Dashboard

async function getAnalytics() {
const [stats, collections] = await Promise.all([
client.stats(),
client.listCollections(0, 100)
]);

if (stats.isSuccess() && collections.isSuccess()) {
const statsBody = stats.getBody();
const collectionsBody = collections.getBody();

return {
totalCollections: collectionsBody.collections?.length || 0,
totalDocuments: statsBody.documents?.total || 0,
memoryUsage: statsBody.memory,
uptime: statsBody.uptime
};
}

return null;
}

Best Practices

  1. Always check response status: Use isSuccess() before accessing response body
  2. Handle errors gracefully: Use try-catch blocks and check for specific exception types
  3. Use pagination: For large result sets, implement pagination
  4. Batch operations: Use import() for bulk document operations
  5. Cache collections: Cache collection schemas to avoid repeated API calls
  6. Use appropriate timeouts: Set reasonable timeout values for your use case
  7. Monitor performance: Track response times and error rates

Status Command

The status command provides concise server information:

node example.js status

This will show:

  • Health status
  • Server statistics
  • Protocol codes
  • Server status
  • Root status response

Next Steps