I’m looking for help to systematically extract information from sub-dictionaries provided by an webAPI. In PowerQuery, these subdictionaries appear as Lists within their parent records. If there is a Key-Value pair in that list, I’d like to extract the value into cell within a named column representing the associated Key. This cell would effectively be a value for the parent record.
I have tried a few techniques but I seem to be getting stumped because:
null
, the Key-value pair are NOT included in the List/Sub-dictionaryHere's a Pseudo-Code description of what I’m envisioning.
> For some known set of known/expected keys
> For each known “Known/expected Key”,
> Find index of “Known/expected Key” and extract it’s associated value
> Add this value to the column named “Known Expected key” in line with the row for that parent record
> If no match is found, add null / empty value to the column named "Known Expected key” for that parent record
^ I expect this same code/logic could be extendable for each new column or key that’s added to my sub-directory dataset over time. <- If there’s some way to tweak the logic such that it can automatically add/handle newly added key-value pairs to these sub-dictionaries, that would be great too.
Here's a snippet of the JSON Data that I've used for testing some solutions:
{
"resources": [{
"name": "Account and Restricted have values",
"shipping_name": null,
"status": "new",
"uuid": "1c59e25c-7505-429e-9e75-9f3837fa65f2",
"custom_field_values": [{
"custom_field_id": "acccount_number",
"value": "5555"
}, {
"custom_field_id": "restricted_access",
"value": "true"
}
]
}, {
"name": "Account and Restricted have values, Division is ",
"shipping_name": null,
"status": "new",
"uuid": "98ac37cf-6e7b-4032-884e-5a9f969fb366",
"custom_field_values": [{
"custom_field_id": "division_number",
"value": ""
}, {
"custom_field_id": "restricted_access",
"value": "true"
}, {
"custom_field_id": "acccount_number",
"value": "666"
}
]
}, {
"name": "Division and Restricted Access have values",
"shipping_name": null,
"status": "new",
"uuid": "f2e0efce-de5d-40ff-b6b1-08c06555456e",
"custom_field_values": [{
"custom_field_id": "division_number",
"value": "DIV4"
}, {
"custom_field_id": "restricted_access",
"value": "true"
}
]
}, {
"name": "Just Account Number has value",
"shipping_name": null,
"status": "new",
"uuid": "ae35f8a7-d130-400c-836a-2cee0fdc8f1b",
"custom_field_values": [{
"custom_field_id": "acccount_number",
"value": "1111311"
}
]
}, {
"name": "Neither Account Number, Division Number. Restricted Access has value FALSE",
"shipping_name": null,
"status": "new",
"uuid": "a1ff1106-3906-484e-8845-1f2b8d12fdcc",
"custom_field_values": [{
"custom_field_id": "restricted_access",
"value": "false"
}
]
}, {
"name": "Neither Account Number, Division Number, nor Restricted Access have values (Example A)",
"shipping_name": null,
"status": "new",
"uuid": "11714504-b78f-40b8-9e9d-a72f2a8db1e4",
"custom_field_values": []
}, {
"name": "Account and Division numbers Only have values",
"shipping_name": null,
"status": "new",
"uuid": "734fbb64-5b34-4d48-acc9-67fdfebd19d3",
"custom_field_values": [{
"custom_field_id": "division_number",
"value": "LLL7"
}, {
"custom_field_id": "acccount_number",
"value": "7777"
}
]
}, {
"name": "Just Division Number has value",
"shipping_name": null,
"status": "new",
"uuid": "2792cf7f-4311-4269-bc10-a6e0b5597947",
"custom_field_values": [{
"custom_field_id": "division_number",
"value": "Just Division Number 9"
}
]
}, {
"name": "Just Restricted Access has value",
"shipping_name": null,
"status": "new",
"uuid": "54b90cf5-3bd4-479f-ac0e-520498929a9e",
"custom_field_values": [{
"custom_field_id": "restricted_access",
"value": "true"
}
]
}, {
"name": "Account, Division, and Restricted Access ALL have values (Example 2)",
"shipping_name": null,
"status": "new",
"uuid": "1b84625f-37b5-4c1f-8e51-1b35efe4c55d",
"custom_field_values": [{
"custom_field_id": "division_number",
"value": "JJJJJ8"
}, {
"custom_field_id": "acccount_number",
"value": "88888"
}, {
"custom_field_id": "restricted_access",
"value": "true"
}
]
}, {
"name": "Account, Division, and Restricted Access ALL have values (Example 1)",
"shipping_name": null,
"status": "new",
"uuid": "60697ec4-23dc-4c2b-aace-4e2e05d7f07d",
"custom_field_values": [{
"custom_field_id": "division_number",
"value": "PPPP9"
}, {
"custom_field_id": "acccount_number",
"value": "999999"
}, {
"custom_field_id": "restricted_access",
"value": "true"
}
]
}
]
}
Here's how the Lists are shown before my attempts to unpack them: Excel PowerQuery showing the List(s) as values within the parent records before being unpacked
I'm hoping for a table like this at the "Parent" level (I only sketched out 2 of the examples from my test data set):
name | shipping name | status | uuid | division_number | account_number | restricted_access |
---|---|---|---|---|---|---|
Account, Division, and Restricted Access ALL have values (Example 1) | new | 60697ec4-23dc-4c2b-aace-4e2e05d7f07d | PPPP9 | 999999 | TRUE | |
Just Account Number has value | new | 2792cf7f-4311-4269-bc10-a6e0b5597947 | 1111311 |
= Table.AddColumn(#"Renamed Columns2", "Custom", each try Record.Field([custom_field_values]{1}, "value") otherwise "")
Using above JSON as input file with Powerquery code:
let Source = Json.Document(File.Contents("C:\Temp\a,json.")),
resources = Table.FromRecords(Source[resources]),
convertcolumn = Table.TransformColumns(resources,{{"custom_field_values", each Table.FromRecords(_)}}),
ColumnsToExpand =List.Distinct(List.Combine(List.Transform(Table.Column(convertcolumn , "custom_field_values"), each if _ is table then Table.ColumnNames(_) else {}))),
#"Expanded custom_field_values" = Table.ExpandTableColumn(convertcolumn, "custom_field_values", ColumnsToExpand,ColumnsToExpand )
in #"Expanded custom_field_values"
generates this output:
you could then pivot it, or just be fancy and directly do
let Source = Json.Document(File.Contents("C:\Temp\a,json.")),
resources = Table.FromRecords(Source[resources]),
convertcolumn = Table.TransformColumns(resources,{{"custom_field_values", each Table.PromoteHeaders(Table.Transpose(Table.FromRecords(_)))}}),
ColumnsToExpand =List.Distinct(List.Combine(List.Transform(Table.Column(convertcolumn , "custom_field_values"), each if _ is table then Table.ColumnNames(_) else {}))),
#"Expanded custom_field_values" = Table.ExpandTableColumn(convertcolumn, "custom_field_values", ColumnsToExpand,ColumnsToExpand )
in #"Expanded custom_field_values"
and get