Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Elasticsearch CRUD is a small set of HTTP operations on JSON documents: index (create or replace), get (read), update (change selected fields), and delete (remove). Use PUT /index/_doc/id when your application owns the ID, POST /index/_doc when Elasticsearch should generate one, _update for partial changes, and conditional parameters when a stale read must not overwrite a newer write. The procedures below cover single-document requests, bulk NDJSON, refresh behavior, data streams, permissions, and failure handling.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
The document model and a safe starting point
An Elasticsearch application stores JSON documents inside indices. A document has an index, an identifier, and a JSON source. The document APIs include Index, Get, Delete, Update, Bulk, Multi-get, Update-by-query, and Delete-by-query. CRUD becomes predictable when you decide three things before writing data:
| # | Preview | Product | Price | |
|---|---|---|---|---|
| 1 |
|
Elasticsearch in Action | $41.13 | Buy on Amazon |
| 2 |
|
Elasticsearch: The Definitive Guide: A Distributed Real-Time Search and Analytics Engine | $24.02 | Buy on Amazon |
| 3 |
|
Elasticsearch in Action, Second Edition | $45.62 | Buy on Amazon |
| 4 |
|
ElasticSearch Cookbook | $63.99 | Buy on Amazon |
As an Amazon Associate I earn from qualifying purchases.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11- Identity: choose a stable application ID or let Elasticsearch generate one.
- Write semantics: choose create-only, complete replacement, or a partial/scripted update.
- Concurrency policy: decide whether an unconditional write is acceptable or whether the last read’s sequence number and primary term must be checked.
Define mappings and choose those IDs before loading production data. A mapping change made after documents exist can require a separate migration, so treating the index design as part of the write workflow avoids accidental type conflicts.
Create documents with the Index API
Use an explicit ID with PUT
When the application already has a durable identifier, put the document at that identifier:
#1 Best Overall
PUT /products/_doc/42
Content-Type: application/json
{"name":"Keyboard","price":99.0}
The request creates document 42 in products. If that ID already exists, the Index API replaces the document source and increments its version; it is therefore an overwrite-style operation, not create-only. Send the complete replacement source when replacement is intended.
Let Elasticsearch generate an ID with POST
POST /products/_doc
Content-Type: application/json
{"name":"Keyboard","price":99.0}
Use this form when the caller does not own the identifier. The generated ID must be captured from the response if another part of the application will later read, update, or delete that document.
Recommended Free Tools
Prevent replacement when an ID already exists
For create-only behavior, add op_type=create to the request or use a create action in a bulk request. If the identifier is already present, the create operation fails with a conflict instead of replacing the existing source. This is the correct choice for idempotent imports where an existing record should be investigated rather than silently overwritten.
PUT /products/_doc/42?op_type=create
Content-Type: application/json
{"name":"Keyboard","price":99.0}
Choose replacement versus update deliberately
| Intent | API form | What happens to fields not sent | Version/no-op behavior |
|---|---|---|---|
| Create or replace the complete document | PUT /products/_doc/42 |
They disappear because the supplied source is the replacement source. | A new version is created even when the source is unchanged. |
| Create only | PUT ...?op_type=create or bulk create |
The existing document is not replaced. | An existing ID causes a conflict. |
| Change selected fields | POST /products/_update/42 |
Unmentioned fields remain. | Use detect_noop when avoiding a write for an unchanged partial update matters. |
Read documents and account for refresh
Get one document by ID
GET /products/_doc/42
The response tells you whether the document was found and, when available, includes its _source. Use this endpoint when the identifier is known and you need the stored document rather than a search result.
Read several known IDs
Use the multi-get API for a set of known identifiers instead of issuing unrelated single-document requests. The request can specify the index once and list the IDs to retrieve:
GET /products/_mget
Content-Type: application/json
{"ids":["42","43","44"]}
Handle each returned item independently: a missing ID is a valid per-document outcome even when other IDs were found.
Do not confuse a write with search visibility
Search visibility is governed by refresh behavior. A workflow that must search for a just-written document can request an explicit refresh, but doing so on every write adds write overhead. If immediate search visibility is not required, allow normal refresh scheduling. A direct document get and a search-after-write check are different workflow requirements; choose refresh behavior for the latter rather than reflexively refreshing every request.
Update without losing unrelated fields
Apply a partial document change
The Update API accepts a partial doc object. Existing fields not included in that object remain in the document:
POST /products/_update/42
Content-Type: application/json
{"doc":{"price":89.0}}
This is safer than sending a shortened source through the Index API when the application intends to change only one property.
Rank #2
Use Painless for an atomic transformation
When the new value depends on the current value, send a Painless script and parameters. The following decrements stock in the update operation:
POST /products/_update/42
Content-Type: application/json
{"script":{"source":"ctx._source.stock -= params.n","params":{"n":1}}}
Keep the transformation in the script rather than performing a read, calculating a value in application code, and issuing an unconditional replacement. That read-modify-write pattern is vulnerable to a concurrent writer unless you add optimistic concurrency controls.
Use upsert behavior when a document may be absent
Update requests can include an upsert document for the not-found case. Bulk update actions support doc, script, upsert, and doc_as_upsert. Choose one intentionally: an upsert creates a defined initial document, while doc_as_upsert uses the partial document as that initial source.
Know when Index is still the right update
If the application has a complete authoritative representation, sending that complete source through Index is straightforward and deterministic. It always creates a new version, including when the source has not changed. If avoiding a needless write is important, use Update with no-op detection rather than relying on Index to detect identical content.
Delete one document or delete by criteria
Delete a known ID
DELETE /products/_doc/42
This removes one known document. Treat the response as an operation result and record failures for retry or investigation.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesDelete documents matching a query
For criteria-based removal, use Delete by query. Start with the equivalent search query and inspect a small sample before executing the destructive request. For example, if a mapping has a boolean discontinued field:
POST /products/_delete_by_query
Content-Type: application/json
{"query":{"term":{"discontinued":true}}}
Replace the example field with the actual field and value in your index. A broad query can remove far more data than intended, so verify the index target, filter, and expected match set before running it.
Process many CRUD actions with Bulk NDJSON
Build the two-line action format
Bulk requests use newline-delimited JSON (NDJSON). Each index, create, or update action has an action line followed by a source or update line. A delete action has no following source line:
POST /_bulk
Content-Type: application/x-ndjson
{"index":{"_index":"products","_id":"1"}}
{"name":"Mouse","price":25}
{"update":{"_index":"products","_id":"1"}}
{"doc":{"price":20}}
{"delete":{"_index":"products","_id":"2"}}
Bulk supports index, create, update, and delete. It reduces request overhead for independent operations, but it does not make every item succeed or fail as one transaction.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #3
Preserve line boundaries with curl
Store the NDJSON payload in a file with a final newline and send it with --data-binary:
curl -X POST "http://localhost:9200/_bulk"
-H "Content-Type: application/x-ndjson"
--data-binary @bulk.ndjson
Using a mode that rewrites newlines can corrupt the action/source pairing. Keep each action on its own line and do not add commas or array brackets.
Inspect every item result
The bulk response contains a per-item result array. Parse that array and handle each action independently: one failed create, update, or delete does not imply that neighboring actions failed. Record the item identifier, operation, and error, then retry only operations that are safe to retry. A bulk create conflict, for example, should not be retried as an unconditional index because that would change the intended create-only semantics.
Protect read-modify-write flows with optimistic concurrency
Why an unconditional write can be stale
Suppose client A reads document 42, client B changes its price, and client A later writes the old complete source. Without a condition, A can overwrite B’s newer change. Elasticsearch assigns a sequence number and primary term to document operations so a client can prove that its write is based on the version it last read.
Send the last sequence number and primary term
Take _seq_no and _primary_term from the last read, then include them in the write:
PUT /products/_doc/42?if_seq_no=7&if_primary_term=3
Content-Type: application/json
{"name":"Keyboard","price":89.0}
If another operation changed the document, the condition no longer matches. Elasticsearch returns HTTP 409 and does not apply the stale write. The application should fetch the current document, merge or reject the user’s change according to business rules, and then retry with the newly observed concurrency values if appropriate.
Apply concurrency controls to bulk operations
Bulk index and delete actions can carry the same sequence-number and primary-term conditions. Bulk update also supports retry_on_conflict for bounded retries. Use a small, deliberate retry limit and still inspect the final per-item result; retries are not a substitute for resolving a conflicting business edit.
Special case: documents in data streams
The normal indexing API cannot update an existing document in a data stream. To update or delete a data-stream document, target the backing index that contains that document. Identify the backing index as part of your operational workflow, and ensure the account has permission to address it. A request aimed only at the data-stream name is not a general replacement for a backing-index update or delete.
Permissions and automatic index creation
With security enabled, grant only the privileges required by the operation and target index:
Rank #4
| Operation | Privileges that can be required |
|---|---|
| Index a document | create, index, or write |
| Create-only request | create_doc can be required |
| Delete a document | delete or write |
| Update a document | index or write |
| Automatic index creation | auto_configure, create_index, or manage, according to the security configuration |
Permission failures can look like CRUD bugs when the endpoint and JSON are correct. Check the authenticated principal’s privilege on the concrete index, including a data stream’s backing index, before changing the request body.
A practical CRUD workflow
- Design first: define mappings and select stable IDs for every entity.
- Choose the write contract: use create-only for immutable imports, Index for complete replacement, or Update for partial and scripted changes.
- Create or index: use explicit IDs when the application owns identity; otherwise capture generated IDs from POST responses.
- Read deliberately: use Get or multi-get for known IDs and decide whether a search immediately after writing truly needs an explicit refresh.
- Update safely: use
doc, scripts, or upsert forms; use sequence-number and primary-term conditions for read-modify-write operations. - Delete narrowly: verify a query against a sample before Delete by query, and use a direct ID delete when the target is known.
- Batch independent work: send valid NDJSON with
--data-binary, then inspect every item result rather than trusting the HTTP-level response alone. - Handle conflicts and permissions: treat HTTP 409 as a stale-write signal, and verify least-privilege access for the operation and target index.
Common failure modes and fixes
An existing document was unexpectedly replaced
The request used Index without op_type=create. Switch to create-only semantics when replacement is not allowed, or use Update if the intent was to change selected fields.
A field disappeared after an update
A complete source was sent through Index even though the caller supplied only a subset of fields. Resend the authoritative complete document, or use Update with a partial doc for future changes.
A search cannot find a document just written
The write may not yet be visible to search because refresh is not immediate. Request an explicit refresh only for workflows that require immediate search visibility; otherwise wait for normal refresh scheduling.
A bulk request reports mixed results
Bulk actions are independent. Parse the per-item result array, preserve each error and ID, and retry only the failed actions with the same intended semantics.
A write returns HTTP 409
The supplied sequence-number and primary-term condition is stale, or a create-only request encountered an existing ID. For optimistic concurrency, read the current document and resolve the merge; for create-only conflicts, decide whether the duplicate is expected and avoid silently converting the operation into replacement.
An update or delete against a data stream fails
Target the backing index that stores the document. The ordinary indexing API is not an update path for an existing data-stream document.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →The endpoint is correct but authorization fails
Check the principal’s index privileges: updates need index or write, deletes need delete or write, and create-only requests can need create_doc. If the index does not yet exist, verify the configured automatic-index-creation privilege as well.
Quick Recap
Choosing the right CRUD approach
| Situation | Recommended approach | Main trade-off |
|---|---|---|
| One known document, complete authoritative state | Index with an explicit ID | Simple replacement, but omitted fields are removed and unchanged sources still create a new version. |
| One known document, only a few fields change | Update with doc |
Preserves other fields; use no-op detection when avoiding unchanged writes matters. |
| Value depends on current state | Scripted Update | Performs the transformation in Elasticsearch; concurrency conditions may still be needed for business-level conflict handling. |
| Many independent operations | Bulk NDJSON | Lower request overhead, but every item must be checked because outcomes can be mixed. |
| Search must immediately see a write | Explicit refresh for that workflow | Improves visibility timing at the cost of additional write overhead. |
| Stale reads must never overwrite newer data | if_seq_no and if_primary_term |
Conflicts become HTTP 409 responses that the application must resolve. |
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




