Only remove/Exclude an attribute from json if it exists

1k views Asked by At

I have following JSON and I would like to remove streets from the JSON object if only it exists under Address which is an array. I am trying to do this in powershell. I can get my script working and remove the streets but I only want to run the exclude line of command if the address has the streets property. Is that possible?

{
    "Customer": [{
        "id": "123"
    }],
    "Nationality": [{
        "name": "US",
        "id": "456"
    }],
    "address": [{
            "$type": "Home",
            "name": "Houston",
            "streets": [{
                "name": "Union",
                "postalCode": "10"
            }]
        },
        {
            "$type": "Home5",
            "name": "Houston5"
        },
        {
            "$type": "Office",
            "name": "Hawai",
            "streets": [{
                "name": "Rock",
                "postalCode": "11"
            }]
        }
    ]
}

Powershell script

$FileContent = Get-Content -Path "Test.json" -Raw | ConvertFrom-Json
#Only want to run for address objects that contains streets
$FileContent.address = $FileContent.address | Select-Object * -ExcludeProperty streets #Only would like to run if object address has streets property
$FileContent | ConvertTo-Json

1

There are 1 answers

0
mklement0 On BEST ANSWER

Note:

  • This answer performs the same operation as in the question, only more succinctly, in a single pipeline.

  • It is benign to run Select-Object * -ExcludeProperty streets against all objects in array address, because the call is an effective no-op for those objects that already lack a streets property (though a copy of such objects is created too).


You need an assignment to modify your objects in-place before outputting them, which requires a ForEach-Object call:

Get-Content -Raw Test.json | ConvertFrom-Json | 
  ForEach-Object { 
    [array] $_.address = $_.address | select * -exclude streets; $_ 
  }

Note how each object parsed from the JSON input is first modified via the assignment ($_.address = ...), and then passed out ($_).

A more efficient, but a little more obscure variant:

Get-Content -Raw Test.json | ConvertFrom-Json | 
  ForEach-Object { 
    $_.address.ForEach({ $_.psobject.Properties.Remove('streets') }); $_ 
  }

With your sample JSON input, both commands output the following:

Customer    Nationality          address
--------    -----------          -------
{@{id=123}} {@{name=US; id=456}} {@{$type=Home; name=Houston}, @{$type=Home5; name=Houston5}, @{$type=Office; name=Hawai}}

Note how the objects in the address column no longer have a streets property.

Caveat: Note that ConvertTo-Json limits the serialization depth to 2 by default, which is sufficient in this case, but in other cases you may have to pass a -Depth argument to prevent data loss - see this post.