Pulling out an item from an array based on a property more than 1 level deep?

Viewed 53

Say I have an array of metadata items. The json data of such would look something like this:

[
    {
        "attributes": {
            "created": "20/08/2020",
            "valid": true,
            "name": "foobar"
        },
        "id": 1
    },
    {
        "attributes": {
            "created": "22/08/2020",
            "valid": true,
            "name": "foobar"
        },
        "id": 3
    }
]

What I'd like to do is find the metadata item in the array that has the newest created data and return the whole of the item metadata item (i.e. such that I still have access to the other fields of the metadata).

I was trying to do something like this: $myArray | Sort-Object -Property attributes.created | Select-Object -Last 1

But this doesn't work as -Property only seems to be able to be used with properties one level deep only.

I guess I'm trying to get the Powershell equivalent of the C# var itemIWant = myArray.OrderByDescending(o => o.attributes.created).First();

How can I achieve this?

1 Answers

As demonstrated in some of the other answers you can sort by an expression to get at the sub-property. Might look something like:

$JSON =
@"
[
    {
        "attributes": {
            "created": "20/08/2020",
            "valid": true,
            "name": "foobar"
        },
        "id": 1
    },
    {
        "attributes": {
            "created": "22/08/2020",
            "valid": true,
            "name": "foobar"
        },
        "id": 3
    }
]
"@

$Objects = ConvertFrom-Json $JSON

$Objects | 
Sort-Object -Property { [DateTime]::ParseExact( $_.Attributes.Created,  "dd/MM/yyyy", $null )  } | 
Select-Object -Last 1

Note: That that you have to convert the "Created" Property to a [DateTime] object to sort properly. That said the parsing approach in the other answers may not work unless you tell it how to parse it. In this example I user ParseExact() which in testing seems to do the trick.

Given that the objects being returned from ConverFrom-Json don't have the "Created" property correctly typed, you may want to recast it before you even sort. That might depend on if you are going to do anything else with the object collection. There are probably several ways to do this, but here's one approach picking up after the ConvertFrom-Json command:

$Objects.ForEach( { $_.Attributes.created = [DateTime]::ParseExact( $_.Attributes.Created,  "dd/MM/yyyy", $null ) } )

Now the "Created" property will be an actual [DateTime] object and you can sort compare etc... as you would any other date.

$Objects | Sort-Object -Property { $_.attributes.created } | Select-Object -Last 1
Related