Omega
Omega

Reputation: 871

Terraform iterate over list of dicts

In have a list of dicts of which one key contains another list. I want to create an object that I can use in for_each which would repeat key1, key2, list_key as many times as there are list items.

What would be the best way to iterate over it?

my_list = [
   {
    "key1"     = "value1"
    "key2"     = "value2"
    "list_key" = ["l_value1", "l_value2"]
   },
   {
    "key1"     = "value3"
    "key2"     = "value4"
    "list_key" = ["l_value3"]
   }
]

I tried flattening it in my locals using this method, but when I use it in for_each it says for_each supports maps and sets of strings, but you have provided a set containing type object.

locals {
    params = flatten([
       for element in var.my_list:
         [
          for k in element["list_key"]:
           {
             "key1"     = element["key1"]
             "key2"     = element["key2"]
             "list_key" = k
           }
         ]
       ]
     )
   }

I'd then like to use it in my resource:

resource "an_aws_service" "my_service" {
    for_each       = toset(local.params)
    name           = each.value.key1
    something      = each.value.key2
    something_else = each.value.list_key
}

If the output looked like this I could probably work with it with toset, but maybe there are other ways to flatten it:

[{
    "key1"     = "value1"
    "key2"     = "value2"
    "list_key" = "l_value1"
},
{
    "key1"     = "value1"
    "key2"     = "value2"
    "list_key" = "l_value2"
},
{
    "key1"     = "value3"
    "key2"     = "value4"
    "list_key" = "l_value3"
}]

Upvotes: 0

Views: 2325

Answers (1)

Ervin Szilagyi
Ervin Szilagyi

Reputation: 16775

Your code with flattening

locals {
  params = flatten([
    for element in var.my_list :
    [
      for k in element["list_key"] :
      {
        "key1"     = element["key1"]
        "key2"     = element["key2"]
        "list_key" = k
      }
    ]
    ]
  )
}

...produces a list of objects (as the error message says, and also as you are pointing it out in your question):

name = [
  {
    "key1" = "value1"
    "key2" = "value2"
    "list_key" = "l_value1"
  },
  {
    "key1" = "value1"
    "key2" = "value2"
    "list_key" = "l_value2"
  },
  {
    "key1" = "value3"
    "key2" = "value4"
    "list_key" = "l_value3"
  },
]

If you want to use this array to create multiple resources, you either transform this array into a map:

resource "an_aws_service" "my_service" {
    for_each       = { for index, value in local.params : index => value }
    name           = each.value.key1
    something      = each.value.key2
    something_else = each.value.list_key
}

Or use count instead of for_each:

resource "an_aws_service" "my_service" {
    count          = length(local.params)
    name           = local.params[count.index].key1
    something      = local.params[count.index].key2
    something_else = local.params[count.index].list_key
}

You can not use a list of objects in a for_each. You either have to have a map (first example) or use count instead of for_each.

Upvotes: 2

Related Questions