NEW

Pulse 2025 Product Roundup: From Monitoring to AI-Native Control Plane

Elasticsearch Exists Query: Syntax, Parameters, and Examples - Syntax, Example, and Tips

The Elasticsearch exists query matches documents where the named field has at least one indexed, non-null value. It is the standard way to test for field presence (exists) and, when nested in a must_not clause, for field absence. The query operates on the inverted index and doc values, not on _source, so its result depends on the field's mapping and on options like ignore_above and ignore_malformed.

Syntax

GET /index/_search
{
  "query": {
    "exists": {
      "field": "field_name"
    }
  }
}

Parameters

Parameter Description Required Default
field Name of the field to test. Dot notation is supported for object sub-fields. Yes -

The exists query exposes no other top-level parameters. To negate it, wrap it in a bool.must_not.

Examples

Find documents that have a user field with at least one indexed value:

GET /events/_search
{
  "query": {
    "exists": { "field": "user" }
  }
}

Find documents missing a field, using bool.must_not:

GET /events/_search
{
  "query": {
    "bool": {
      "must_not": [
        { "exists": { "field": "user.email" } }
      ]
    }
  }
}

Combine with a filter so the absence check is unscored and cacheable:

GET /events/_search
{
  "query": {
    "bool": {
      "filter": [
        { "range": { "@timestamp": { "gte": "now-7d/d" } } }
      ],
      "must_not": [
        { "exists": { "field": "user_id" } }
      ]
    }
  }
}

Probe a nested object's field (use a nested query for true nested mappings):

GET /orders/_search
{
  "query": {
    "nested": {
      "path": "shipments",
      "query": {
        "exists": { "field": "shipments.tracking_number" }
      }
    }
  }
}

Performance and Use Notes

A field is considered to exist if it has any indexed value. The official docs list four conditions under which a field is reported as missing: the source value was null or []; the field has index: false and doc_values: false; a value was longer than ignore_above and was skipped; or the value was malformed and ignore_malformed is enabled. Empty strings ("") and a placeholder like "-" count as existing values - they are real terms in the index.

The query is cheap. It is backed by the _field_names index field (for indexed fields) and by doc-values existence (for fields with doc_values: true). Both data structures are present by default for the standard text/keyword/numeric/date types, so exists on a normal field is roughly as fast as a term query. Run it in filter context to enter the per-node query cache.

Mapping or ingest issues sometimes cause a field to appear in _source but never get indexed - making it invisible to exists. Pulse monitors Elasticsearch indices for mapping drift, dropped fields, and ignore_malformed/ignore_above events, so silent data-quality regressions surface before they break dashboards.

Common Mistakes

  1. Expecting exists to read _source. It checks indexed values. A field with index: false and doc_values: false is invisible to the query even when present in the JSON.
  2. Storing explicit null and expecting exists to match. JSON null and [] are treated as missing - use a sentinel value if you must distinguish "explicit null" from "absent".
  3. Forgetting that ignore_above (default unlimited for keyword) and ignore_malformed cause values to be dropped silently from the index.
  4. Running exists against the parent path of a nested field. Wrap it in a nested query instead.
  5. Using exists in must instead of filter for negative-presence checks. The score adds nothing; use filter/must_not to keep the query cacheable.

Frequently Asked Questions

Q: How do I find documents where a field does not exist?
A: Wrap the exists query in a bool.must_not. Elasticsearch removed the standalone missing query in 5.0, so this combination is the supported pattern. Place the must_not inside bool and add a filter clause to scope the negative match to a reasonable set.

Q: Does the exists query treat empty strings as missing?
A: No. Empty strings ("") and placeholders like "-" are indexed as real terms and count as existing. Only JSON null, an empty array [], fields with no indexed/doc value, and values dropped by ignore_above/ignore_malformed are missing.

Q: How does the exists query behave with arrays?
A: An array that contains at least one non-null element counts as existing - ["foo", null] matches. An empty array [] or [null] does not.

Q: Can I use the exists query in filter context?
A: Yes, and you should. It needs no relevance score, so running it in bool.filter (or bool.must_not for the negative case) lets it enter the per-node query cache.

Q: Why does exists return zero hits when the field clearly exists in _source?
A: The field is not indexed. Likely causes: index: false plus doc_values: false in the mapping, an ignore_above truncation, a malformed value with ignore_malformed: true, or a dynamic mapping that placed the field under an unexpected path.

Q: How is exists different from a term query on the field?
A: exists answers "does this document have any value here", while a term query answers "does this document have this specific value". They are also implemented differently - exists uses the _field_names field or doc-values existence, not the term dictionary.

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.