OriginChainDB docs
elasticsearch · bulk

Bulk ingest and safe concurrent writes

_bulk returns HTTP 200 even when individual items fail — so read errors and each item’s own status. To stop two writers overwriting each other, carry if_seq_no and if_primary_term on an index action: the write lands only if the document is still the version you read.

Load many documents

Newline-delimited actions, exactly as a cluster takes them. An index that does not exist yet is created by the first write.

await es.bulk({ operations: [
  { 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 }
]})

Read the result per item

A bulk request is 200 even when some items fail; errors tells you whether any did, and each item carries its own status. Check it — a failed item in a successful request is the classic silent data-loss bug.

const res = await es.bulk({ operations })
if (res.errors) {
  for (const item of res.items) {
    const op = item.index ?? item.update ?? item.delete
    if (op.status >= 300) console.error(op._id, op.status, op.error?.type)
  }
}

Guard a write against a concurrent one

Carry if_seq_no and if_primary_term on an action and the write lands only if the document is still the version you read. A stale precondition comes back as a per-item 409 and every other item in the batch still applies, so the loser retries one document rather than the whole load.

// read the document you are about to change
const cur = await es.get({ index: 'shop.products', id: 'sku-8842' })

await es.bulk({ operations: [
  { index: { _index: 'shop.products', _id: 'sku-8842',
             if_seq_no: cur._version - 1, if_primary_term: 1 } },
  { ...cur._source, price: 129 }
]})

// stale -> items[0].index.status === 409
//          version_conflict_engine_exception
where preconditions apply

On index actions. A create is already its own precondition (the document must not exist), so it does not take a version. A conditional update or delete is refused: an update is a read-modify-rewrite, and asserting the version at the rewrite is a different guarantee from the one your read saw. External versioning is refused too — it has no faithful mapping onto an exact compare-and-set.

Partial updates

update merges: the fields you send are written and every other field is preserved.

await es.bulk({ operations: [
  { update: { _index: 'shop.products', _id: 'sku-8842' } },
  { doc: { price: 139 } }   // name, brand, ... untouched
]})

Throughput

Batches are written through the engine's chunked ingest path rather than one document at a time. Send documents in batches of a few hundred to a few thousand; a single enormous request is not faster and costs you the ability to retry a small piece of it.

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.