@magierin-schnee/solr-client
v1.1.0
Published
A simple and efficient Solr client for Node.js applications. Supports Solr 5 through 10+.
Maintainers
Readme
@magierin-schnee/solr-client
A powerful and flexible Node.js client for Apache Solr (versions 5 through 10+), offering an intuitive API for document management, advanced querying, and collection administration.
✨ Features
- Solr 5–10+ Compatible: Works across all modern Solr versions, including Solr 10.
- Custom Request Handlers: Query any handler (
/suggest,/browse, custom handlers) directly via URL path — no reliance on the deprecatedqtparameter. - Full-Featured Document API: Add, update, and delete documents with simple, chainable methods.
- Powerful Query Builder: Construct sophisticated queries with a fluent API.
- JSON Facet API: Full support for terms, range, query, and nested facets.
- Streaming Support: Efficiently index large datasets via streams.
- Collection Management: Administer SolrCloud collections with ease.
- Robust Error Handling: Modern
async/awaitand promise-based error handling.
🚀 Getting Started
1. Installation
npm install @magierin-schnee/solr-client2. Creating a Client
import { createClient } from '@magierin-schnee/solr-client'
const client = createClient({
host: '127.0.0.1',
port: 8983,
core: 'my_core',
path: '/solr',
secure: false,
bigint: false,
})3. Authentication
client.setBasicAuth('username', 'password')
// To remove authentication
client.clearAuth()Core Functionality
Adding Documents
// Single document
await client.addDocuments({ id: '1', name: 'Example' }, { commit: true })
// Multiple documents
await client.addDocuments([
{ id: '2', name: 'Another' },
{ id: '3', name: 'Yet Another' },
], { commit: true })Searching Documents
// Using the default /select handler
const query = client.createQuery().setQuery('name:Example')
const response = await client.searchDocuments(query)
console.log(response.response.docs)
// Get all documents
const all = await client.searchAllDocuments()Custom Request Handlers
For Solr 7+ (and especially Solr 10), the qt parameter is ignored by default. Use searchByHandler() to query custom handlers directly via the URL path:
// Query a custom 'suggest' handler
const query = client.createQuery().setQuery('kia')
const result = await client.searchByHandler('suggest', query)
// Query a custom 'suggestedBrands' handler
const query = client.createQuery()
.setQuery('*:*')
.addFilter('brandSlug:toyota')
const result = await client.searchByHandler('suggestedBrands', query)You can also use executeQuery() for full control:
const result = await client.executeQuery('myCustomHandler', query)Retrieving Documents by ID
const response = await client.getDocumentsById('1')
const multi = await client.getDocumentsById(['1', '2', '3'])Deleting Documents
await client.deleteById('1', { commit: true })
await client.deleteByField('name', 'Example', { commit: true })
await client.deleteByQuery('name:Example', { commit: true })
await client.deleteAllDocuments({ commit: true })Committing Changes
await client.commit()
await client.softCommit()
await client.prepareCommit()Querying
Build complex queries using the Query class:
const query = client
.createQuery()
.setQuery('*:*')
.addFilter('age:25')
.setOffset(0)
.setLimit(10)
.setSort({ score: 'desc' })
const response = await client.searchDocuments(query)Key Query Methods
| Method | Description | Example |
| ------------------------- | ----------------------------------------- | ---------------------------------------------------------------------- |
| setQuery(query) | Sets the main query string. | .setQuery('name:Example') |
| addFilter(filter) | Adds a filter query (fq). | .addFilter('category:books') |
| addFilters(filters) | Adds multiple filter queries. | .addFilters(['inStock:true', 'price:[* TO 100]']) |
| setOffset(offset) | Sets the starting offset for pagination. | .setOffset(10) |
| setLimit(limit) | Limits the number of results. | .setLimit(20) |
| setSort(fields) | Defines sort order. | .setSort({ score: 'desc' }) |
| setResponseFields(fields) | Specifies fields to return. | .setResponseFields(['id', 'name']) |
| setFacets(config) | Configures faceting (JSON Facet API). | .setFacets({ categories: { type: 'terms', field: 'cat', limit: 10 } }) |
| setHighlighting(config) | Configures highlighting. | .setHighlighting({ on: true, fl: 'content' }) |
| setParam(key, value) | Sets any arbitrary Solr parameter. | .setParam('defType', 'edismax') |
| useExtendedDisMax() | Enables the eDisMax query parser. | .useExtendedDisMax() |
Advanced Facets
Full support for Solr's JSON Facet API:
Terms Facet
const query = client.createQuery()
.setQuery('*:*')
.setLimit(0)
.setFacets({
category: { type: 'terms', field: 'category', limit: 10, mincount: 1 },
})
const response = await client.searchDocuments(query)
// response.facets.category.buckets → [{ val: 'electronics', count: 75 }, ...]Range Facet
const query = client.createQuery()
.setQuery('*:*')
.setLimit(0)
.setFacets({
price: { type: 'range', field: 'price', start: 0, end: 1000, gap: 100 },
})Query Facet
const query = client.createQuery()
.setQuery('*:*')
.setLimit(0)
.setFacets({
inStock: { type: 'query', q: 'inStock:true' },
})Nested Facets
const query = client.createQuery()
.setQuery('*:*')
.setLimit(0)
.setFacets({
ratings: {
type: 'query',
q: '*:*',
facet: {
high: { type: 'query', q: 'rate:[9.0 TO *]' },
good: { type: 'query', q: '+rate:[8.0 TO *] -rate:[9.0 TO *]' },
},
},
})Streaming Documents
const { stream, response } = client.createDocumentStream({ commit: true })
stream.write({ id: '1', name: 'Streamed Document' })
stream.end()
const result = await responseManaging Collections
const collection = client.createCollection()
const response = await client.manageCollection(collection)Error Handling
import { SolrError } from '@magierin-schnee/solr-client'
try {
await client.addDocuments(document)
} catch (error) {
if (error instanceof SolrError) {
console.error('HTTP Status:', error.httpStatusCode)
console.error('Solr Code:', error.solrCode)
console.error('Message:', error.message)
console.error('Metadata:', error.metadata)
}
}Migration from 0.x
Breaking Changes in 1.0.0
executeQuery()is now public — You can callclient.executeQuery(handler, query)directly for full control over which handler receives the request.New
searchByHandler()method — The recommended way to query custom request handlers:// Before (0.x): relied on qt parameter, broken in Solr 7+ const query = client.createQuery().setRequestHandler('suggest').setQuery('kia') const result = await client.searchDocuments(query) // After (1.0): handler goes in the URL path, works on all Solr versions const query = client.createQuery().setQuery('kia') const result = await client.searchByHandler('suggest', query)setRequestHandler()is deprecated — It still works (setsqtparam) but is ignored by Solr 7+ by default. UsesearchByHandler()instead.setParam()is now public — Set any arbitrary Solr parameter directly on the query.escapeLuceneCharsandconvertDatesToISOare now exported from the main entry point.
Non-Breaking Changes
searchDocuments()still works exactly as before (always hits/select).- All existing Query builder methods are unchanged.
- All document operations (add, delete, commit) are unchanged.
SolrErrornow includessolrCodefor the Solr-specific error code.
Solr Version Compatibility
| Solr Version | Status | |---|---| | 5.x | ✅ Tested | | 6.x | ✅ Tested | | 7.x | ✅ Tested | | 8.x | ✅ Tested | | 9.x | ✅ Tested | | 10.x | ✅ Tested |
License
This project is licensed under the MIT License.
