I have a vector ["x" "y" "z"].
I am trying to dynamically create the following:
{:aggs {:bucket-aggregation
{:terms {:field "x"},
:aggs {:bucket-aggregation
{:terms {:field "y"},
:aggs {:bucket-aggregation
{:terms {:field "z"}}}}}}}}
I currently have the following but can't figure out how to make it recursive
(defn testing [terms]
{:aggs {:bucket-aggregation
{:terms {:field (nth terms 0)} (testing (pop terms))}}})
Here's one way to solve:
(def my-vec ["x" "y" "z"])
(defn testing [[head & tail]]
(when head
{:aggs {:bucket-aggregation (merge {:terms {:field head}}
(testing tail))}}))
(testing my-vec)
;=>
;{:aggs {:bucket-aggregation {:terms {:field "x"},
; :aggs {:bucket-aggregation {:terms {:field "y"},
; :aggs {:bucket-aggregation {:terms {:field "z"}}}}}}}}
This works by destructuring the input into a head element and tail elements, so each call is adding a :field
of head
and recursing on the tail
.
And here's another way to solve using reduce
:
(reduce
(fn [acc elem]
{:aggs {:bucket-aggregation (merge {:terms {:field elem}} acc)}})
nil
(reverse my-vec))
This works by reverse
ing the input vector and building the map from the inside-out. This reduce
approach won't result in a stack overflow for large vectors, but the first solution will.