Map Block
The map
block can be used to create complex maps/objects inside Globals and Lets blocks. It can be used to aggregate lists of objects into maps that have duplicated keys and need a defined way of deep merging values of the same key.
The following is a very basic example introducing the map
block inside a globals
block:
globals {
map obj {
for_each = [
{ name = "a", value = 5 },
{ name = "c", value = 0 },
{ name = "a", value = 15 },
{ name = "b", value = 5 },
{ name = "c", value = 20 },
]
iterator = elem
key = elem.new.name
value {
value = elem.new.value
previous = tm_try(elem.old.value, null)
}
}
}
The code above will result in the global.obj
defined below:
obj = {
a = {
previous = 5
value = 15
}
b = {
previous = null
value = 5
}
c = {
previous = 0
value = 20
}
}
The map
will iterate over the values in for_each
, setting the iterator variable (elem
in this case, element
by default) with the elem.new
and elem.old
values for the provided key
. The elem.new
contains the current iterated value and the elem.old
contains the values of the previous iteration of the current key
.
Now it's time for a more useful example.
Take a look at the global.orders
list declared below:
globals {
orders = [
{ name = "Morpheus", product = "sunglass", price = 100.5 },
{ name = "Trinity", product = "cape", price = 82.30 },
{ name = "Trinity", product = "necklace", price = 25.0 },
{ name = "Trinity", product = "sunglass", price = 100.5 },
{ name = "Anderson", product = "ollydbg", price = 30 },
{ name = "Morpheus", product = "boot", price = 65 },
{ name = "Anderson", product = "cape", price = 82.30 },
{ name = "Morpheus", product = "sunglass", price = 145.50 },
]
}
Let's aggregate those values by name
, by using the map
block as defined below:
globals {
map totals {
for_each = global.orders
key = element.new.name
value {
total_spent = tm_try(element.old.total_spent, 0) + element.new.price
}
}
}
Which will result in the global object below:
totals = {
Anderson = {
total_spent = 112.3
}
Morpheus = {
total_spent = 311
}
Trinity = {
total_spent = 207.8
}
}
Using nested map
blocks and then aggregating by product
for each name
can be achieved using the following:
Example:
globals {
map totals {
for_each = global.orders
iterator = per_name
key = per_name.new.name
value {
total_spent = tm_try(per_name.old.total_spent, 0) + per_name.new.price
map per_product {
for_each = [for v in global.orders : v if v.name == per_name.new.name]
iterator = per_product
key = per_product.new.product
value {
total = tm_try(per_product.old.total, 0) + per_product.new.price
}
}
}
}
}
which will result the object below:
obj = {
Anderson = {
total_spent = 112.3
per_product = {
cape = {
total = 82.3
}
ollydbg = {
total = 30
}
}
}
Morpheus = {
total_spent = 311
per_product = {
boot = {
total = 65
}
sunglass = {
total = 246
}
}
}
Trinity = {
total_spent = 207.8
per_product = {
cape = {
total = 82.3
}
necklace = {
total = 25
}
sunglass = {
total = 100.5
}
}
}
}