Search code examples
loopselasticsearchtemplatesmustache

ElasticSearch : Is it possible to loop with mustache in a ElasticSearchTemplate


In an ElasticSearch Template , I would like to to that :

  "aggs": {
        "att_characteristic": {
          "filters": {
            "filters": {
              {{#agg-att}}
              "{{code}}" : {"term": { "characteristic.code": "{{code}}"}}{{^last}}, {{/last}}
              {{/agg-att}}
            }
          },
          "aggs": {
            "agg_by_value": {
              "terms": {
                "field": "characteristic.value",
                "size": 10000
              },
              "aggs": {
                "top_reverse_nested": {
                  "reverse_nested": {}
                }
              }
            }
          }
        }
      }

But I am getting the following error:

   "reason" : "Improperly closed variable in query-template:1 @[query-template:1]"

It bugs at :

{{#agg-att}}
  "{{code}}" : {"term": { "characteristic.code": "{{code}}"}}{{^last}}, {{/last}}
{{/agg-att}}

Can we loop in an ElasticSearch Template with Mustache language as in another language?

PS : It is called with

GET index-name-dev/_search/template
{
  "id": "search-template-test",
  "params": {
    "agg-att":[{"code":"Color"},
               {"code":"Shape"},
               {"code":"Size"}]
  }
}

Thanks !

UPDATE : Here below is a full example

The mapping is the following :

PUT tly-idx_test1
{
  "mappings": {
    "properties": {
      "fieldA": {
        "type": "keyword"
      },
      "fieldArrayA": {
        "type": "keyword"
      },
     "fieldArrayB": {
      "type": "nested",
      "properties": {
        "color": {
          "type": "keyword",
          "fields": {
            "text": {
              "type": "text",
              "analyzer": "standard"
              }
            }
          },
          "size": {
            "type": "keyword",
            "fields": {
              "text": {
                "type": "text",
                "analyzer": "standard"
                }
              }
          },
          "shape": {
            "type": "keyword",
            "fields": {
              "text": {
                "type": "text",
                "analyzer": "standard"
                }
              }
            },
          "value": {
            "type": "keyword",
            "fields": {
              "text": {
                "type": "text",
                "analyzer": "standard"
                }
              }
            },
          "obligatoire": {
            "type": "boolean"
            }
        }
     },
      "fieldB": {
        "type": "text"
      },
      "fieldC": {
        "type": "text"
      },
      "fieldD": {
        "type": "text"
      },
      "fieldE": {
        "type": "boolean"
      }
    }
  }
}

Here below is some data to put in the test index

POST tly-idx_test1/_doc
{
  "fieldA": "M",
  "fieldB": "SHOWER PACK",
  "fieldC": "false",
  "fieldD": "01",
  "fieldE": "true",
  "fieldArrayA": [
    "val1",
    "val2",
    "val3"
  ],
   "fieldArrayB": [
    {"color":"red","size":"10cm","shape":"square","obligatoire":true,"value":"15"},
    {"color":"blue","size":"100cm","shape":"circle","obligatoire":true ,"value":"25"},
    {"color":"green","size":"50cm","shape":"rectangle","obligatoire":true ,"value":"35"},
    {"color":"yellow","size":"22cm","shape":"triangle","obligatoire":true ,"value":"45"}
    
  ]
}

Here below is the template

GET tly-idx_test1/_search
{
  "query": {
    "match_all": {}
  },
  "aggregations": {
    "agg-attributs": {
      "nested": {
        "path": "fieldArrayB"
      },
      "aggs": {
        "att_obligatoire": {
          "filters": {
            "filters": {
              {{#agg-att}}
              "{{code}}" : {"term": { "fieldArrayB.color": "{{code}}"}}{{^last}}, {{/last}}
              {{/agg-att}}
            }
          },
          "aggs": {
            "agg_by_value": {
              "terms": {
                "field": "fieldArrayB.value",
                "size": 10000
              },
              "aggs": {
                "top_reverse_nested": {
                  "reverse_nested": {}
                }
              }
            }
          }
        }
      }
    }
  }
}

Compressed :

PUT _scripts/tly-template-test
{
  "script": {
    "lang": "mustache",
    "source": "{\"query\":{\"match_all\":{}},\"aggregations\":{\"agg-attributs\":{\"nested\":{\"path\":\"fieldArrayB\"},\"aggs\":{\"att_obligatoire\":{\"filters\":{\"filters\":{{{#agg-att}}\"{{code}}\":{\"term\":{\"fieldArrayB.color\":\"{{code}}\"}}{{^last}},{{/last}}{{/agg-att}}}},\"aggs\":{\"agg_by_value\":{\"terms\":{\"field\":\"fieldArrayB.value\",\"size\":10000},\"aggs\":{\"top_reverse_nested\":{\"reverse_nested\":{}}}}}}}}}}"
  }
}

Finally, here below is the template calling :

GET tly-idx_test1/_search/template
{
  "id": "tly-template-test",
  "params": {
    "agg-att": [{"code": "color"},
                {"code": "shape"},
                {"code": "size","last": true}
    ]
  }
}

I got the same error

"reason" : "Improperly closed variable in query-template:1 @[query-template:1]"

Why does the loop does not work?


Solution

  • You're almost there, you just forget to specify last in the last element

    GET index-name-dev/_search/template
    {
      "id": "search-template-test",
      "params": {
        "agg-att": [
          {
            "code": "Color"
          },
          {
            "code": "Shape"
          },
          {
            "code": "Size",
            "last": true            <---- add this
          }
        ]
      }
    }
    

    UPDATE:

    The problem is in your compressed version some curly braces are too close to one another and that goes in the way of some mustache syntax rules (two {{ and three {{{ don't mean the same thing)

    You need to add one space here

    ...{\"filters\":{ {{#agg-att}}\"{{code}}\":{\"term\":{\"fieldArrayB.color\":\"{{code}}\"}}...
                     ^
                     |
                 add space
    

    and another here

    ...{{^last}},{{/last}}{{/agg-att}} }},...
                                      ^
                                      |
                                  add space
    

    Which is why it's always better and more legible to use a fully formatted template, like the one below:

    POST _scripts/tly-template-test
    {
      "script": {
        "lang": "mustache",
        "source": """
      {
        "query":{
          "match_all":{}
        },
        "aggregations":{
          "agg-attributs":{
            "nested":{
              "path":"fieldArrayB"
            },
            "aggs":{
              "att_obligatoire":{
                "filters":{
                  "filters":{
                    {{#agg-att}}
                      "{{code}}":{
                        "term":{
                          "fieldArrayB.color":"{{code}}"
                        }
                      }{{^last}},{{/last}}
                    {{/agg-att}}
                  }
                },
                "aggs":{
                  "agg_by_value":{
                    "terms":{
                      "field": "fieldArrayB.value",
                      "size":10000
                    },
                    "aggs":{
                      "top_reverse_nested":{
                        "reverse_nested":{}
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
        """
      }
    }