Flatten indirectly-nested lists of two different names

Hi,

I have a variable in terraform.auto.tfvars that looks like this:

teams = [
  {
    name = "team1"
    members = [
      "member1",
      "member2"
    ]
    maintainers = [
      "maintainer1",
      "maintainer2"
    ]
  }
]

I want to flatten it to looks like this:

d = [
  {
    "member_name" = "maintainer1"
    "member_role" = "maintainer"
    "team_name" = "team1"
  },
  {
    "member_name" = "maintainer2"
    "member_role" = "maintainer"
    "team_name" = "team1"
  },
  {
    "member_name" = "member1"
    "member_role" = "member"
    "team_name" = "team1"
  },
  {
    "member_name" = "member2"
    "member_role" = "member"
    "team_name" = "team1"
  },
]

I can achieve that as follows, but I am sure there must be an easier way to do this in one pass, rather than three.

locals {
  a = flatten([for v1 in var.teams :
    {
      name        = v1.name
      members     = v1.members
      maintainers = v1.maintainers
    }
  ])

  b = flatten([for v1 in local.a : [
    for v2 in v1.maintainers :
    {
      team_name   = v1.name
      member_name = v2
      member_role = "maintainer"
    }
  ]])

  c = flatten([for v1 in local.a : [
    for v2 in v1.members :
    {
      team_name   = v1.name
      member_name = v2
      member_role = "member"
    }
  ]])

  d = concat(local.b, local.c)
}

output "d" {
  value = local.d
}

can anyone advise on how I can make my locals better?

I recommend that the flattened version would be a map rather list of maps. This way you have deterministic keys and the order doesn’t matter. If you use list of maps then your indexes can change and have side effects in Terraform.

locals {
  teams = [
    {
      name = "team1"
      members = [
        "member1",
        "member2"
      ]
      maintainers = [
        "maintainer1",
        "maintainer2"
      ]
    }
  ]

  # recommended data model!
  flat_object = { for k, v in flatten([for team in local.teams :
    [
      [for member in try(team.members, []) : {
        "member_name" = member
        "member_role" = "member"
        "team_name"   = team.name
      }],
      [for maintainer in try(team.maintainers, []) : {
        "member_name" = maintainer
        "member_role" = "maintainer"
        "team_name"   = team.name
      }]
    ]
  ]) : "${v.team_name}_${v.member_role}_${v.member_name}" => v }

  # I would avoid this data model
  flat_list = [for i in flatten([for team in local.teams :
    [
      [for member in try(team.members, []) : {
        "member_name" = member
        "member_role" = "member"
        "team_name"   = team.name
      }],
      [for maintainer in try(team.maintainers, []) : {
        "member_name" = maintainer
        "member_role" = "maintainer"
        "team_name"   = team.name
      }]
    ]
  ]) : i]
}

output "flat_object" {
  value = local.flat_object
}

output "flat_list" {
  value = local.flat_list
}

Thanks very much. I will try this out.