A nested type is what you are looking for, and don't worry about performance.
Before indexing documents, you need to establish a mapping for your documents:
curl -XDELETE localhost:9200/index curl -XPUT localhost:9200/index curl -XPUT localhost:9200/index/type/_mapping -d '{ "type": { "properties": { "field_x": { "type": "nested", "include_in_parent": false, "include_in_root": false, "properties": { "user": { "type": "string" }, "field_x": { "type": "string", "index" : "not_analyzed" // NOTE* } } } } } }'
* note: If your field really contains only special letters such as "A" and "B", you do not want to analyze the field, otherwise elasticsearch will delete these letters of the "word". If this was just your example and you are looking for the right words in your actual documents, delete this line and ask elasticsearch to parse the field.
Then index your docs:
curl -XPUT http://localhost:9200/index/type/1 -d ' { "field_a": "foo", "field_b": "bar", "field_x" : [{ "user" : "1", "field_x" : "A" }, { "user" : "2", "field_x" : "B" }] }'
And run your query:
curl -XGET localhost:9200/index/type/_search -d '{ "query": { "nested" : { "path" : "field_x", "score_mode" : "avg", "query" : { "bool" : { "must" : [ { "term": { "field_x.user": "1" } }, { "term": { "field_x.field_x": "A" } } ] } } } } }';
This will lead to
{"took":13,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":1.987628,"hits":[{"_index":"index","_type":"type","_id":"1","_score":1.987628, "_source" : { "field_a": "foo", "field_b": "bar", "field_x" : [{ "user" : "1", "field_x" : "A" }, { "user" : "2", "field_x" : "B" }] }}]}}
However request
curl -XGET localhost:9200/index/type/_search -d '{ "query": { "nested" : { "path" : "field_x", "score_mode" : "avg", "query" : { "bool" : { "must" : [ { "term": { "field_x.user": "1" } }, { "term": { "field_x.field_x": "B" } } ] } } } } }';
will not return any results
{"took":6,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}