Home > Mobile >  powershell - filter nested object which contains data from list
powershell - filter nested object which contains data from list

Time:11-17

I am looking for a way to filter nested objects with PowerShell. Let's say I have a list that contains UPN addresses.

$UPN = "[email protected]", "[email protected]"

In the below object converted to JSON, I want to get only those objects where "Attr1" within whole object contains any address from the above list.

[
    {
        "Id":  "1",
        "Name":  "XYZ",
        "Attr1":  [
                      {
                          "Id":  "1",
                          "UPN":  "[email protected]"
                      },
                      {
                          "Id":  "2",
                          "UPN":  "[email protected]"
                      },
                      {
                          "Id":  "3",
                          "UPN":  "[email protected]"
                      }
                  ],
        "Attr2":  [
                        {
                            "Id":  "1",
                            [...]
                        }
                    ],
        "Attr3":  [
                         {
                             "Id":  "1",
                             [...]
                         },
                         {
                             "Id":  "2",
                             [...]
                        
                         }
                     ]
    },
    {
        "Id":  "2",
        "Name":  "XYZ",
        "Attr1":  [
                      {
                          "Id":  "1",
                          "UPN":  "[email protected]"
                      }
                  ],
        "Attr2":  [
        
                    ],
        "Attr3":  [
                         {
                             "Id":  "1",
                             [...]
                         }
                     ]
    }
]

How to filter such an object? The standard method to not work for me (I am not getting the desired result, losing data):

$CollectionOfObjects | Where-Object {$_.Attr1.UPN -in $UPN} 

How to handle this?

Regards!

CodePudding user response:

You need to nest Where-Object calls to get the desired result, or, for better performance with in-memory collections, .Where() method calls:

$CollectionOfObjects.Where({ $_.Attr1.Where({ $_.UPN -in $UPN }, 'First') })

Tip of the hat to Manuel Batsching for his help.

Note: The 'First' argument isn't strictly necessary, but can improve performance, as it stops enumerating the elements of the array in .Attr1 as soon as a match is found.

As an aside: Where-Object has no equivalent feature - enumeration invariably continues.
GitHub issue #13834 suggests bringing all the extra features .Where() supports to Where-Object too.


A self-contained example with simplified data:

$UPN = '[email protected]', '[email protected]'

$CollectionOfObjects = ConvertFrom-Json @'
[
  {
      "Id":  "1",
      "Name":  "XYZ1",
      "Attr1":  [
                    {
                        "Id":  "1",
                        "UPN":  "[email protected]"
                    },
                    {
                        "Id":  "2",
                        "UPN":  "[email protected]"
                    },
                    {
                        "Id":  "3",
                        "UPN":  "[email protected]"
                    }
                ],
      "Attr2":  [ ],
      "Attr3":  [ ]
  },
  {
    "Id":  "2",
    "Name":  "XYZ2",
    "Attr1":  [
                  {
                      "Id":  "1",
                      "UPN":  "[email protected]"
                  },
                  {
                      "Id":  "2",
                      "UPN":  "[email protected]"
                  }
              ],
    "Attr2":  [ ],
    "Attr3":  [ ]
  },
  {
      "Id":  "3",
      "Name":  "XYZ3",
      "Attr1":  [
                    {
                        "Id":  "1",
                        "UPN":  "[email protected]"
                    }
                ],
      "Attr2":  [ ],
      "Attr3":  [ ]
  }
]
'@

$CollectionOfObjects.Where({ $_.Attr1.Where({ $_.UPN -in $UPN }, 'First') })

Output, showing that the two objects of interest were successfully identified:

Id    : 1
Name  : XYZ1
Attr1 : {@{Id=1; [email protected]}, @{Id=2; [email protected]}, @{Id=3; [email protected]}}
Attr2 : {}
Attr3 : {}

Id    : 3
Name  : XYZ3
Attr1 : {@{Id=1; [email protected]}}
Attr2 : {}
Attr3 : {}
  • Related