Search code examples
elasticsearchspring-data-elasticsearch

How to fetch only specific object inside nested field along with search query in Elasticsearch


I am having an index which has nested fields. I want to include only particular nested object in response based on condition along with other fields. For example consider the mappings

    PUT /users
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "address": {
        "type": "nested",
        "properties": {
          "state": {
            "type": "keyword"
          },
          "city": {
            "type": "keyword"
          },
          "country": {
            "type": "keyword"
          }
        }
      }
    }
  }

I want to search users by name and expecting the response should only include nested object contains country = 'United States". Consider the following documents in users index

 {
        "users": [
            {
                "name": "John",
                "address": [
                    {
                        "state": "Alabama",
                        "city": "Alabaster",
                        "Country": "United States"
                    },
                    {
                        "state": "New Delhi",
                        "city": "Agra",
                        "Country": "India"
                    }
                ]
            },
            {
                "name": "Edward John",
                "address": [
                    {
                        "state": "Illinois",
                        "city": "Chicago",
                        "Country": "United States"
                    },
                    {
                        "state": "Afula",
                        "city": "Afula",
                        "Country": "Israel"
                    }
                ]
            },
,
            {
                "name": "Edward John",
                "address": [
                    {
                        "state": "Afula",
                        "city": "Afula",
                        "Country": "Israel"
                    }
                ]
            }
        ]
    }

I am expecting the search result as follows

  {
        "users": [
            {
                "name": "John",
                "address": [
                    {
                        "state": "Alabama",
                        "city": "Alabaster",
                        "Country": "United States"
                    }
                ]
            },
            {
                "name": "Edward John",
                "address": [
                    {
                        "state": "Illinois",
                        "city": "Chicago",
                        "Country": "United States"
                    }
                ]
            },
,
            {
                "name": "Edward John",
                "address": [
                ]
            }
        ]
    }

Kindly provide me a suitable elasticsearch query to fetch this documents


Solution

  • The correct query would be this one:

    POST users/_search
    {
      "_source": [
        "name"
      ],
      "query": {
        "bool": {
          "should": [
            {
              "nested": {
                "path": "address",
                "query": {
                  "bool": {
                    "must": [
                      {
                        "match": {
                          "address.Country": "United States"
                        }
                      }
                    ]
                  }
                },
                "inner_hits": {}
              }
            },
            {
              "bool": {
                "must_not": [
                  {
                    "nested": {
                      "path": "address",
                      "query": {
                        "bool": {
                          "must": [
                            {
                              "match": {
                                "address.Country": "United States"
                              }
                            }
                          ]
                        }
                      }
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    }
    

    Which returns this:

      "hits" : {
        "total" : {
          "value" : 3,
          "relation" : "eq"
        },
        "max_score" : 1.489748,
        "hits" : [
          {
            "_index" : "users",
            "_type" : "_doc",
            "_id" : "X8pINHgB2VNT6r1rJj04",
            "_score" : 1.489748,
            "_source" : {
              "name" : "John"
            },
            "inner_hits" : {
              "address" : {
                "hits" : {
                  "total" : {
                    "value" : 1,
                    "relation" : "eq"
                  },
                  "max_score" : 1.489748,
                  "hits" : [
                    {
                      "_index" : "users",
                      "_type" : "_doc",
                      "_id" : "X8pINHgB2VNT6r1rJj04",
                      "_nested" : {
                        "field" : "address",
                        "offset" : 0
                      },
                      "_score" : 1.489748,
                      "_source" : {
                        "city" : "Alabaster",
                        "Country" : "United States",
                        "state" : "Alabama"
                      }
                    }
                  ]
                }
              }
            }
          },
          {
            "_index" : "users",
            "_type" : "_doc",
            "_id" : "XftINHgBAEsNDPLQQxL8",
            "_score" : 1.489748,
            "_source" : {
              "name" : "Edward John"
            },
            "inner_hits" : {
              "address" : {
                "hits" : {
                  "total" : {
                    "value" : 1,
                    "relation" : "eq"
                  },
                  "max_score" : 1.489748,
                  "hits" : [
                    {
                      "_index" : "users",
                      "_type" : "_doc",
                      "_id" : "XftINHgBAEsNDPLQQxL8",
                      "_nested" : {
                        "field" : "address",
                        "offset" : 0
                      },
                      "_score" : 1.489748,
                      "_source" : {
                        "city" : "Chicago",
                        "Country" : "United States",
                        "state" : "Illinois"
                      }
                    }
                  ]
                }
              }
            }
          },
          {
            "_index" : "users",
            "_type" : "_doc",
            "_id" : "UoZINHgBNlJvCnAGVzE9",
            "_score" : 0.0,
            "_source" : {
              "name" : "Edward John"
            },
            "inner_hits" : {
              "address" : {
                "hits" : {
                  "total" : {
                    "value" : 0,
                    "relation" : "eq"
                  },
                  "max_score" : null,
                  "hits" : [ ]
                }
              }
            }
          }
        ]
      }