Filter elements from object

Hi,

I’m trying to filter output from a module (see module output bellow) but I still dont get correct elements.

Here is what I have:

module "static_ips" {
  source  = "./foo"
}

output "orig" {
  value = module.static_ips
}
output "result" {
  value  = [ for i, v in tomap(module.static_ips) : i if  v != "RESERVED" ]
}

Can someone point me in right direction how to implement this? Thx in advance!

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

orig = {
  "self_link" = [
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-0",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-1",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-2",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-3",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-4",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-5",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-6",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-7",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-8",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-9",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-10",
    "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-11",
  ]
  "status" = [
    "RESERVED",
    "RESERVED",
    "RESERVED",
    "RESERVED",
    "IN_USE",
    "IN_USE",
    "IN_USE",
    "IN_USE",
    "IN_USE",
    "IN_USE",
    "RESERVED",
    "RESERVED",
  ]
}
result = [
  "self_link",
  "status",
]

I have solved it by using a submodule with zipmap.

Here is a solution if someone is interested: terraform-gcp-modules/static_address at main · drdkadtr/terraform-gcp-modules · GitHub

Hi @drdkadtr!

Thanks for following up to confirm that you found a solution.

In case someone else finds this topic in future, I want to add some notes about what was going on in your first case and thus specifically why your first attempt didn’t work.

In output "result" the for expression is based on tomap(module.static_ips). We can see from output "orig" that module.static_ips is an object with self_link and status attributes, both of which are lists of strings, and so converting this value to a map would produce a map(list(string)) value.

However, the if clause of the for expression says v != "RESERVED", which is comparing v to a string value. All v in this map are list(string), so that expression will always return true, and so the final value of output "result" is indeed just a list of the attributes of the original object: ["self_link", "status"].

Because the intent here was to correlate the elements from module.static_ips.self_link with the elements from module.static_ips.status using matching indices, zipmap can serve as a concise solution to transform this pair of lists of the same length into a map from self links to statuses:

zipmap(module.static_ips.self_link, module.static_ips.status)

Another way to achieve that result would be the following for expression:

{ for i, link in module.static_ips.self_link : link => module.static_ips.status[i] }

Which to use is just a matter of style preference; there is no significant functional difference. In both cases, the result would be shaped like this:

{
  "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-0" = "RESERVED"
  "https://www.googleapis.com/compute/v1/projects/foo/regions/europe-west2/addresses/foo-nat-external-address-1" = "RESERVED"
  # (etc)
}

That map therefore matches what your original for expression was expecting: a map from identifiers to statuses, so that you can filter out the ones where status is "RESERVED".

I know I’m not telling you anything you didn’t already figure out here, since I can see you doing similar things in your example, but as noted above this comment is mainly for a hypothetical person who finds this topic in future and is interested in why your solution worked, and why your original attempt did not.

Thx @apparentlymart,

Your comments are always greatly appreciated!
I have added additional version without zipmap() func call if some should need:

BR, -A