Skip to main content
Related: Indexer, CLI, Troubleshooting Delete documents by filter from a collection. Use relation‑level convenience for “delete what I just filtered”, model‑level helpers for ad‑hoc deletes, or the low‑level API when you need full control.
Safety: With no filters, relation deletion uses a safe match‑all filter id:!=null. Prefer targeted filters; consider Indexer → Stale Deletes for recurring cleanup flows with guardrails.

Relation‑level: delete_all

# Delete all published=false books (compiled to filter_by)
SearchEngine::Book.where(published: false).delete_all

# Override physical collection and partition context if needed
SearchEngine::Book
  .where(publisher_id: 123)
  .delete_all(into: "books_20251011_120000_001", partition: 123, timeout_ms: 5_000)
  • Compiles current where AST to filter_by and sends DELETE /documents.
  • When the relation has no predicates, falls back to id:!=null (match‑all).
  • Options:
    • into: physical collection name (skip alias resolution)
    • partition: forwarded to the resolver (see below)
    • timeout_ms: read timeout override for the delete call

Flow

Model‑level: delete_by

Use either a filter string or a Hash that will be converted safely.
# String form
SearchEngine::Book.delete_by("archived:=true && publisher_id:=123")

# Hash form (converted via Sanitizer)
SearchEngine::Book.delete_by(archived: true, publisher_id: 123)

# With options
SearchEngine::Book.delete_by(
  { archived: true }, into: "books_20251011_120000_001", partition: 123, timeout_ms: 2_000
)
Rules:
  • Provide either a non‑blank String or a non‑empty Hash. An empty input raises.
  • into: overrides the target physical collection.
  • partition: is passed to the resolver (see next section).
  • Return value is the number of deleted documents the server reports.

Instance‑level: delete (single record)

Delete a single hydrated record by its document id.
book = SearchEngine::Book.find_by(book_id: 123123)
book.delete # => 1 when deleted, 0 when nothing matched

# Options (parity with relation delete_all)
book.delete(into: "books_20251011_120000_001", partition: 123, timeout_ms: 2_000)
Notes:
  • The record id is taken from hydrated id when present, otherwise computed via the model’s identify_by strategy.
  • If the id cannot be determined, an error is raised.
  • Calling delete on a Relation is not supported; use delete_all.

Low‑level helper: SearchEngine::Deletion.delete_by

SearchEngine::Deletion.delete_by(
  klass: SearchEngine::Book,
  filter: "archived:=true",
  into: nil, partition: nil, timeout_ms: nil
)

Into resolution

The target collection is resolved in order:
  • Explicit into: option when provided
  • Contextual into from instrumentation (used during schema apply/indexation)
  • SearchEngine.config.partitioning.default_into_resolver if configured
  • Fallback to the model’s logical collection name (klass.collection)
This allows deletes to target a just‑created physical during blue/green apply before the alias is swapped.

Timeouts

timeout_ms: overrides the read timeout. When omitted, it falls back to SearchEngine.config.stale_deletes.timeout_ms when set; otherwise the client default is used.

When to use Indexer stale deletes

Prefer Indexer → Stale Deletes when you routinely delete by a known filter. It offers:
  • Centralized stale rules on the model (declared inside index)
  • Strict‑mode guardrails to block suspicious catch-alls
  • Optional estimation and events for observability
Use relation/model deletion for one‑off cleanup or admin tooling where you have the exact filter already.

Troubleshooting

  • Empty input: delete_by requires a filter string or a non‑empty hash
  • Deleted 0 docs unexpectedly: check into: (physical vs alias) and filter
  • Partitioned setups: pass partition: so your resolver can pick a target
  • Timeouts: increase timeout_ms for large deletes
Backlinks: Home, CLI, Indexer, Troubleshooting