HelloPablo
HelloPablo

Reputation: 625

Elasticsearch: Query nested object contained within an object

I'm struggling to build a query where I can do a nested search across a sub-object of a document.

Say I have the following index/mapping:

curl -XPOST "http://localhost:9200/author/" -d '
{
    "mappings": {
        "item": {
            "properties": {
                "books": {
                    "type": "object",
                    "properties": {
                        "data": {
                            "type": "nested"
                        }
                    }
                }
            }
        }
    }
}
'

And the following 2 documents in the index:

{
    "id": 1,
    "name": "Robert Louis Stevenson",
    "books": {
        "count": 2,
        "data": [
            {
                "id": 1,
                "label": "Treasure Island"
            },
            {
                "id": 3,
                "label": "Dr Jekyll and Mr Hyde"
            }
        ]
    }
}

and

{
    "id": 2,
    "name": "Philip K. Dick",
    "books": {
        "count": 1,
        "data": [
            {
                "id": 4,
                "label": "Do Android Dream of Electric Sheep"
            }
        ]
    }
}

I have an array of Book ID's, say [1,4]; how would I write a query which does a keyword search of the author name AND only returns them if they wrote one of the books in the array?

I haven't managed to get a query which doesn't cause some sort of query parse_exception, but as a starting block, here's the current iteration of my query - maybe it's obvious where I'm going wrong?

{
    "query": {
        "bool": {
            "must": {
                "match": {
                    "label": "Louis"
                }
            }
        },
        "nested": {
            "path": "books.data",
            "query": {
                "bool": {
                    "must": {
                        "terms": {
                            "books.data.id": [
                                1,
                                4
                            ]
                        }
                    }
                }
            }
        }
    },
    "from": 0,
    "size": 8
}

In the above scenario I'd like the document for Mr Robert Louis Stevenson to be returned, as his name contains Louis and he wrote book ID 1.

For what it's worth, the current error I get looks like this:

{
   "error": {
      "root_cause": [
         {
            "type": "parse_exception",
            "reason": "failed to parse search source. expected field name but got [START_OBJECT]"
         }
      ],
      "type": "search_phase_execution_exception",
      "reason": "all shards failed",
      "phase": "query",
      "grouped": true,
      "failed_shards": [
         {
            "shard": 0,
            "index": "author",
            "node": "sCk3su4YSnqhvdTGjOztlw",
            "reason": {
               "type": "parse_exception",
               "reason": "failed to parse search source. expected field name but got [START_OBJECT]"
            }
         }
      ]
   },
   "status": 400
}

This makes me feel like I've got my "nested" object all wrong, but the docs suggest that I'm right!

Upvotes: 0

Views: 754

Answers (1)

Val
Val

Reputation: 217304

You have it almost right, the nested query must simply be located inside the bool one like in the query below. Also the match query needs to be made on the name field since this is where the author name is stored:

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "Louis"
          }
        },
        {
          "nested": {
            "path": "books.data",
            "query": {
              "bool": {
                "must": {
                  "terms": {
                    "books.data.id": [
                      1,
                      4
                    ]
                  }
                }
              }
            }
          }
        }
      ]
    }
  },
  "from": 0,
  "size": 8
}

Upvotes: 2

Related Questions