'Elastic search query to filter documents based on the top value of nested array
The document has this structure:
{
innerArray: [
{set: "A", value: 123},
{set: "A", value: 234},
{set: "B", value: 115},
{set: "C", value: 133},
{set: "C", value: 256},
...
]
}
With a rather complex nested query, I can return documents where innerArray has elements both in set A and with value above a specified limit (e.g. 200). I can also order the inner_hits by value.
This query returns documents that have ANY inner_hits that match the criteria.
{
"query": {
"bool": {
"filter": [
{
"nested": {
"path": "innerArray",
"inner_hits": {
"sort": { "innerArray.value": { "order": "asc" } }
},
"query": {
"bool": {
"filter": [
{ "term": { "innerArray.set": "A" }},
{ "range": { "innerArray.value" : { "gt": 200 } } }
]
}
}
}
}
]
}
}
}
Now, I need only those where the FIRST inner_hit (filtered on 'set' and ordered by 'value') has a value above 200. In pseudo SQL you could use a query with a HAVING clause but you could also write something like this:
select doc
from documents
where (
select min(value)
from doc.innerArray
where set = 'A'
) > 200
Is this feasible in elastic? How can I write such a query?
Solution 1:[1]
You would need to use Nested aggregation, a special single bucket aggregation that enables aggregating nested documents.
Query:
GET /_search
{
"query": {
"bool": {
"filter": [
{
"nested": {
"path": "innerArray",
"inner_hits": {
"sort": { "innerArray.value": { "order": "asc" } }
},
"query": {
"bool": {
"filter": [
{ "term": { "innerArray.set": "A" }},
{ "range": { "innerArray.value" : { "gt": 200 } } }
]
}
}
}
}
]
}
}
},
"aggs": {
"resellers": {
"nested": {
"path": "innerArray"
},
"aggs": {
"min_value": {
"min": {
"field": "innerArray.value"
}
}
}
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Kaveh |