OriginChainDB

Elasticsearch examples

← All examples

These recipes use the Elasticsearch-compatible API on dedicated deployments. Read current support and authentication before connecting.

Create products, then inspect search resultsThese examples use the documented Elasticsearch-compatible adapter on dedicated deployments.
  1. Declare the mappingCreate the product index with its field types.
  2. Load three productsCheck every bulk item and apply the sample price update.
  3. Search and countInspect product hits and the Aero and Metro groups.
  4. Delete lastPreview the matching count before the bounded deletion example.

Run a recipe

  1. Configure the client using the connection guide.
  2. Create the sample index before writing or searching its documents.
  3. Run one request and inspect its response before moving to the next task.

The JavaScript snippets use the 7.x client: requests put payloads in body and read responses from body. Compatibility is limited to the documented forms, not every Elasticsearch client feature. Raw routes are listed in the API reference.

Use one small dataset

Run Create an index, Write a document, Load several documents, then Change selected fields. This creates three products and changes the first product's price to 139. The later search sections use those records.

Try the read examples before the delete example. Deleting the two Aero products changes the answers and removes the document used by the later read-by-ID example. Use a fresh test index or reload the sample before comparing results.

In these snippets, es is the connected JavaScript client from the connection guide. An index is the named searchable collection; a mapping declares the fields it accepts. Each await belongs inside an async function or a module that supports top-level await.

Create an index

Declare the fields and their mapping types before writing documents.

await es.indices.create({
    index: 'shop.products',
    body: {
        mappings: { properties: {
                name: { type: 'text' },
                brand: { type: 'keyword' },
                price: { type: 'integer' }
            } }
    }
})

Write a document

Create or replace the document with the chosen _id. On this adapter path the document is searchable when the write returns; this does not combine independent native row, vector and full-text calls.

await es.index({
    index: 'shop.products',
    id: 'sku-8842',
    body: { name: 'Carbon Marathon', brand: 'Aero', price: 149 }
})

Load several documents

Send a bulk action for each document. The client builds the newline-delimited JSON body from the operations array. Check every item’s result, not only the outer response.

await es.bulk({
    body: [
        { index: { _index: 'shop.products', _id: 'sku-1207' } },
        { name: 'Trail 24', brand: 'Aero', price: 89 },
        { index: { _index: 'shop.products', _id: 'sku-3355' } },
        { name: 'City Runner', brand: 'Metro', price: 72 }
    ]
})

Change selected fields

Send the fields to change. This update merges them into the document and preserves other fields.

await es.update({
    index: 'shop.products',
    id: 'sku-8842',
    body: {
        doc: { price: 139 } // name, brand, ... untouched
    }
})

Search document text

Use match to turn the query into searchable words with the field’s text rules. With the three sample products loaded, marathon finds sku-8842. Read the document in each hit’s _source field.

await es.search({
    index: 'shop.products',
    body: {
        query: { match: { name: 'marathon' } }
    }
})

Add exact filters to a search

Put the text query in must and exact or range conditions in filter. Here the product must contain runner, have brand Metro, and cost at most 100. The sample match is sku-3355. Filters restrict matches without adding to the text score.

await es.search({
    index: 'shop.products',
    body: {
        query: { bool: {
                must: [{ match: { name: 'runner' } }],
                filter: [{ term: { brand: 'Metro' } },
                    { range: { price: { lte: 100 } } }]
            } }
    }
})

Count matches by value

A terms aggregation counts documents with the same field value. Before deleting anything, the sample gives two Aero documents and one Metro document. size: 0 omits individual hits because this request only needs those group counts.

await es.search({
    index: 'shop.products',
    body: {
        size: 0,
        aggs: { by_brand: { terms: { field: 'brand' } } }
    }
})

Count matching documents

Use the count endpoint when you need the total without fetching documents. This request should count two Aero products before the delete example runs.

await es.count({
    index: 'shop.products',
    body: {
        query: { term: { brand: 'Aero' } }
    }
})

Read the next page

Sort by price and _id, then pass the last hit’s pair of sort values as search_after. With only three sample products and a page size of 20, the next page is empty. Check that the first page contains a hit before reading .at(-1).sort; stop paging when no hits remain. Pagination remains inside the documented 10,000-hit window.

const { body: page1 } = await es.search({
    index: 'shop.products',
    body: {
        size: 20,
        sort: [{ price: 'asc' }, { _id: 'asc' }],
        query: { match_all: {} }
    }
})

const last = page1.hits.hits.at(-1).sort   // e.g. [72, 'sku-3355']
await es.search({
    index: 'shop.products',
    body: {
        size: 20,
        sort: [{ price: 'asc' }, { _id: 'asc' }],
        search_after: last,
        query: { match_all: {} }
    }
})

Delete a bounded set of matches

This deletes the two Aero products from the sample. Run the matching count first and use max_docs to cap the deletion. Reload those products before continuing with their read-by-ID or spelling examples. Unbounded whole-table deletion is refused.

await es.deleteByQuery({
    index: 'shop.products',
    max_docs: 100,
    body: {
        query: { term: { brand: 'Aero' } }
    }
})

Read one document

Fetch by ID. The response carries _version for conditional writes and supports _source filtering. The _source/:id route returns only the document.

await es.get({ index: 'shop.products', id: 'sku-8842' })
// -> { _index, _id, _version: 2, found: true, _source: { ... } }

await es.getSource({
  index: 'shop.products', id: 'sku-8842', _source_includes: 'price'
})   // -> { price: 139 }

await es.exists({ index: 'shop.products', id: 'sku-8842' })   // true / false

Group results by calendar day

This uses a separate index, shop.orders, with a placed_at date field; the product setup does not create it. Create that mapping and index orders with known dates before testing. Use calendar_interval with ISO-8601 or epoch-millisecond values. Each bucket counts orders within one UTC calendar day. fixed_interval is refused on this path.

Create the two-order sample for this request

Use an unused test index. Do not replace a shop.orders table from a different example.

await es.indices.create({
  index: 'shop.orders',
  body: { mappings: { properties: { placed_at: { type: 'date' } } } }
})

await es.bulk({
  body: [
    { index: { _index: 'shop.orders', _id: 'order-1' } },
    { placed_at: '2026-01-01T10:00:00Z' },
    { index: { _index: 'shop.orders', _id: 'order-2' } },
    { placed_at: '2026-01-01T15:00:00Z' }
  ]
})

Check both bulk item results. The aggregation below should then put two orders into the January 1 UTC day bucket.

await es.search({
    index: 'shop.orders',
    body: {
        size: 0,
        aggs: { per_day: { date_histogram: {
                    field: 'placed_at', calendar_interval: 'day', time_zone: 'UTC'
                } } }
    }
})

Count named groups

Give each filter a name to obtain a count for that group. Sub-aggregations use the same matched documents. other_bucket_key collects matches outside all named filters. Send this aggregation separately from other top-level aggregations.

await es.search({
    index: 'shop.products',
    body: {
        size: 0,
        aggs: { by_price: {
                filters: {
                    other_bucket_key: 'mid_range',
                    filters: {
                        clearance: { range: { price: { lt: 50 } } },
                        premium: { range: { price: { gte: 200 } } }
                    }
                },
                aggs: { avg_price: { avg: { field: 'price' } } }
            } }
    }
})

Show documents inside each group

Use top_hits to include matching documents and their _source fields. The first request finds the sample City Runner. The final aggs: block is only a request-body fragment: place it inside es.search({ index: ..., body: { ... } }) to request one example per brand.

await es.search({
    index: 'shop.products',
    body: {
        size: 0,
        query: { match: { name: 'runner' } },
        aggs: { best: { top_hits: { size: 3 } } }
    }
})

// nested: one top hit per brand
aggs: { by_brand: { terms: { field: 'brand' },
  aggs: { top: { top_hits: { size: 1 } } } } }

Suggest a spelling correction

The term suggester uses words already indexed in the field. missing corrects unknown words; always considers every word. Read each option’s text and score. This adapter does not support phrase or completion suggesters.

await es.search({
    index: 'shop.products',
    body: {
        size: 0,
        suggest: { did_you_mean: {
                text: 'marathn', term: { field: 'name' }
            } }
    }
})

// suggest.did_you_mean[0].options
//   -> [ { text: 'marathon', score: 0.875 } ]

Check versions during bulk writes

Put if_seq_no and if_primary_term on each conditional bulk action. A stale item returns 409 while other items can succeed. Read the current document and reapply the intended change before retrying only the conflicting item.

await es.bulk({
    body: [
        { index: { _index: 'shop.products', _id: 'sku-8842',
                if_seq_no: 1, if_primary_term: 1 } },
        { name: 'Carbon Marathon', brand: 'Aero', price: 129 }
    ]
})

// stale precondition -> items[0].index.status === 409
//                        version_conflict_engine_exception

Elasticsearch is a trademark of Elasticsearch B.V., registered in the U.S. and in other countries. OriginChainDB is not affiliated with, endorsed by, or sponsored by Elasticsearch B.V. OriginChainDB implements a compatible HTTP API so that existing Elasticsearch clients can talk to it; it does not distribute Elasticsearch software.

Next steps

Check supported Elasticsearch features before adapting a production client.

© 2026 Silicoyn Technologies Pvt Ltd

On this page