Search code examples
elasticsearchelasticsearch-dsl

Elasticsearch nested path query into an object type


Having this template (abbreviated version).

{
  "index_patterns": "index_pattern*",
  "order": 1,
  "version": 1,
  "aliases": {
    "some_alias": {}
  },
  "settings": {
    "number_of_shards": 5,
  },
  "mappings": {
    "dynamic": "false",
    "properties": {
      "someId": {
        "type": "keyword"
      },
      "audience": {
        "type": "object",
        "properties": {
          ....
          "ageRanges": {
            "type": "nested",
            "properties": {
              "ageTo": {
                "type": "integer"
              },
              "ageFrom": {
                "type": "integer"
              }
            }
          }
        }
      }
    }
  }
}

I need to query if the audience.ageRanges does not exist or if it does exist apply other filters.

Let's say we want to search if a document with specific someId value fits into the audience.ageRanges query clauses (removed for clarity). It has some audience properties but no ageRanges.

"audience": {
  "genders": [
    "any"
  ],
  "deviceType": "any"
}

Shouldn't the below query return the specific document?

{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "someId": {
                            "value": "03183f31"
                        }
                    }
                },
                {
                    "nested": {
                        "path": "audience.ageRanges",
                        "query": {
                            "bool": {
                                "must_not": [
                                    {
                                        "exists": {
                                            "field": "audience.ageRanges"
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            ]
        }
    }
}

My results are 0, it is a bit confusing how it works.

Trying with a document id that does have audience.ageRanges items and changing the must_not nested query to must will return results.


Solution

  • Instead of putting must_not inside the nested query, you should put the nested query inside the must_not.

    Consider a sample index data as

    {
      "someId":123,
      "audience": {
        "genders": [
          "any"
        ],
        "deviceType": "any"
      }
    }
    

    You need to modify your search query as shown below -

    Search Query:

    {
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "someId": {
                  "value": "123"
                }
              }
            },
            {
              "bool": {
                "must_not": {
                  "nested": {
                    "path": "audience.ageRanges",
                    "query": {
                      "bool": {
                        "must": [
                          {
                            "exists": {
                              "field": "audience.ageRanges"
                            }
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          ]
        }
      }
    }
    

    Search Result:

    "hits": [
          {
            "_index": "65852173",
            "_type": "_doc",
            "_id": "1",
            "_score": 0.2876821,
            "_source": {
              "someId": 123,
              "audience": {
                "genders": [
                  "any"
                ],
                "deviceType": "any"
              }
            }
          }
        ]