Fast-DB Batch Search Client is a TypeScript library for performing efficient batch searches with fuzzy matching support. It allows searching for multiple target items related to a single node (e.g., multiple books by one author).
npm install @fondation-io/fast-db-batch-search-client
import { BatchSearchClient } from '@fondation-io/fast-db-batch-search-client';
const client = new BatchSearchClient({
baseUrl: 'http://localhost:8080',
timeout: 30000,
includeMetrics: true
});
Search for multiple books by one author:
const results = await client.batchSearch(
'books', // table name
'auteurs', // node field (author field)
'J.K. Rowling', // node value (single author)
'titre', // target field (title field)
[ // target values (multiple titles)
'Harry Potter école sorciers',
'Harry Potter chambre secrets',
'Harry Potter prisonnier Azkaban'
],
['titre', 'auteurs', 'annee'], // fields to return
true, // use fuzzy search
5 // max results per title
);
// Response structure
{
results: [ // Flat array of all results
{
search_group_hash: "hash1",
titre: "Harry Potter à l'école des sorciers",
auteurs: "J.K. Rowling",
annee: 1997
},
// ... more results
],
grouped: { // Results grouped by search query
"hash1": [...], // Results for first title
"hash2": [...], // Results for second title
"hash3": [...] // Results for third title
},
totalResults: 15,
metrics: { /* performance data */ }
}
async batchSearch(
table: string, // Table/collection name
nodeField: string, // Field containing node (e.g., author)
nodeQuery: string, // Single node value to search
targetField: string, // Field containing targets (e.g., titles)
targetQueries: string[], // Array of target values to search
projection?: string[], // Fields to return (default: ['*'])
fuzzy?: boolean, // Use fuzzy search (default: true)
resultsPerQuery?: number // Max results per target (default: 10)
)
const books = await client.batchSearch(
'books',
'auteurs',
'Victor Hugo',
'titre',
['Les Misérables', 'Notre-Dame de Paris'],
['titre', 'auteurs', 'annee', 'isbn']
);
const products = await client.batchSearch(
'products',
'category',
'Electronics',
'product_name',
['iPhone 15', 'MacBook Pro', 'AirPods'],
['product_name', 'price', 'brand', 'sku']
);
const movies = await client.batchSearch(
'movies',
'director',
'Christopher Nolan',
'title',
['Inception', 'Interstellar', 'Tenet'],
['title', 'director', 'year', 'rating']
);
For data spread across multiple tables, use batchSearchWithJoins
.
Search for albums by artist across three related tables:
const mozartAlbums = await client.batchSearchWithJoins({
// Tables to join
tables: ['id_artists', 'album_artist', 'albums'],
// Join conditions
joins: [
{
$type: 'inner',
$left: 'id_artists',
$right: 'album_artist',
$on: ['id_artists.id', 'album_artist.artist_id']
},
{
$type: 'inner',
$left: 'album_artist',
$right: 'albums',
$on: ['album_artist.cb', 'albums.cb']
}
],
// Search parameters
nodeField: 'id_artists.artiste', // Artist name field
nodeQuery: 'Mozart', // Artist to search
targetField: 'albums.album', // Album title field
targetQueries: [ // Albums to find
'Symphony No. 40',
'Symphony No. 41',
'Requiem'
],
// Field projection with aliases
projection: {
artist_name: 'artiste',
album_title: 'album',
release_year: 'street_date'
},
fuzzy: true,
resultsPerQuery: 5,
orderBy: { release_year: -1 }
});
// Response has same structure but includes joined data
inner
: Return only matching records from both tablesleft
: Return all from left table, matching from rightright
: Return all from right table, matching from leftfull
: Return all records from both tablesconst albums = await client.searchAlbumsByArtist(
'Beatles',
['Abbey Road', 'Let It Be', 'Revolver'],
5
);
fuzzy: true
, searches use Levenshtein distancesearch_group_hash
results
arraygrouped
object// Optimize by selecting only needed fields
const optimized = await client.batchSearch(
'large_table',
'category',
'Books',
'title',
['Title1', 'Title2'],
['title', 'price'], // Only return 2 fields
true,
3 // Limit results per query
);
try {
const results = await client.batchSearch(...);
} catch (error) {
if (error.message.includes('Network error')) {
// Server unreachable
} else if (error.message.includes('API Error')) {
// Server returned error
}
}
const results = await client.batchSearch(...);
// Process each group separately
for (const [hash, items] of Object.entries(results.grouped)) {
console.log(`Found ${items.length} results for query ${hash}`);
items.forEach(item => {
// Process each result
});
}
const results = await client.batchSearch(...);
const stats = client.getSearchStats(results.grouped);
if (stats.emptyGroups > 0) {
console.log(`${stats.emptyGroups} queries returned no results`);
}
// Generic method for any node-target relationship
const items = await client.searchRelatedItems(
'inventory',
'warehouse',
'Warehouse-A',
'product_code',
['PROD-001', 'PROD-002', 'PROD-003'],
['product_code', 'quantity', 'location']
);
When includeMetrics: true
:
{
metrics: {
total_time_ms: 45,
search_time_ms: 30,
polars_time_ms: 10,
rows_examined: 1000,
rows_returned: 15,
client_elapsed_ms: 50
}
}
resultsPerQuery
limits