Search code examples
jsonpowerquerym

Does (M) Power Query have a Union of Tables?


I am learning M (Power Query Language). I'd like to use M to parse JSON from REST APIs. For example one can use the Stack Overflow REST API. I can see how to drill down into a simple JSON string using say

let
    Source = Json.Document("{ ""glossary"": { ""title"": ""example glossary"", ""GlossDiv"": { ""title"": ""S"", ""GlossList"": { ""GlossEntry"":
        { ""ID"": ""SGML"", ""SortAs"": ""SGML"", ""GlossTerm"": ""Standard Generalized Markup Language"", ""Acronym"": ""SGML"",
          ""Abbrev"": ""ISO 8879:1986"", ""GlossDef"": { ""para"": ""A meta-markup language, used to create markup languages such as DocBook."",
          ""GlossSeeAlso"": [""GML"", ""XML""] }, ""GlossSee"": ""markup"" } } } } }"),
    glossary = Source[glossary],
    GlossDiv = glossary[GlossDiv],
    GlossList = GlossDiv[GlossList],
    GlossEntry = GlossList[GlossEntry],
    ConvertedToTable = Record.ToTable(GlossEntry)
in
    ConvertedToTable

But what happens when I have a list from which I want to drill in and fetch a subproperty and then I want to return all of those like a SQL UNION query. Actually it is more of a For Each type query.

So here is my non-working query that does not do a union but unfortunately glues the second record onto the side

let
    Source = "{""items"":["
       {""tags"":[""vba"",""permissions""],""owner"":
             {""reputation"":49,""user_id"":9073241,""user_type"":""registered"",""accept_rate"":86,""display_name"":""Kam""},
        ""is_answered"":false,""view_count"":4,""answer_count"":0,""score"":0,""question_id"":48229549},
       {""tags"":[""excel"",""vba"",""excel-vba""],""owner"":
             {""reputation"":18,""user_id"":9057704,""user_type"":""registered"",""accept_rate"":29,""display_name"":""Gregory""},
        ""is_answered"":false,""view_count"":6,""answer_count"":0,""score"":0,""question_id"":48229590}
       ]}",
    #"Parsed JSON" = Json.Document(Source),
    items = #"Parsed JSON"[items],
    item0 = items{0},
    owner0 = item0[owner],
    item1 = items{1},
    owner1 = item1[owner],
    #"Converted to Table" = Table.Combine( {Record.ToTable(owner0), Record.ToTable(owner1) })
in
    #"Converted to Table"

What I am really aiming for is this output but not limited to 2 records, but all the records from the list. (The above sample source has been simplified from this REST API StackOverflow questions tagged VBA)

reputation  user_id user_type   accept_rate display_name
49          9073241 registered  86          Kam
18          9057704 registered  29          Gregory

Solution

  • I think you want to pivot your tables before you try to combine them. Try this query, for example.

    let
        Source1 = Json.Document("{""tags"":[""vba"",""permissions""],""owner"":
                 {""reputation"":49,""user_id"":9073241,""user_type"":""registered"",""accept_rate"":86,""display_name"":""Kam""},
            ""is_answered"":false,""view_count"":4,""answer_count"":0,""score"":0,""question_id"":48229549}"),
        Owner1 = Table.Pivot(Record.ToTable(Source1[owner]), List.Distinct(Record.ToTable(Source1[owner])[Name]), "Name", "Value"),
        Source2 = Json.Document("{""tags"":[""excel"",""vba"",""excel-vba""],""owner"":
                 {""reputation"":18,""user_id"":9057704,""user_type"":""registered"",""accept_rate"":29,""display_name"":""Gregory""},
            ""is_answered"":false,""view_count"":6,""answer_count"":0,""score"":0,""question_id"":48229590}"),
        Owner2 = Table.Pivot(Record.ToTable(Source2[owner]), List.Distinct(Record.ToTable(Source2[owner])[Name]), "Name", "Value"),
        #"Appended Query" = Table.Combine({Owner1, Owner2})
    in
        #"Appended Query"
    

    If you just want to expand all of the owners, try a query more like this:

    let
        Source = "{""items"":[{""tags"":[""vba"",""permissions""],""owner"":{""reputation"":49,""user_id"":9073241,""user_type"":""registered"",""accept_rate"":86,""display_name"":""Kam""},""is_answered"":false,""view_count"":4,""answer_count"":0,""score"":0,""question_id"":48229549},{""tags"":[""excel"",""vba"",""excel-vba""],""owner"":{""reputation"":18,""user_id"":9057704,""user_type"":""registered"",""accept_rate"":29,""display_name"":""Gregory""},""is_answered"":false,""view_count"":6,""answer_count"":0,""score"":0,""question_id"":48229590}]}",
        #"Parsed JSON" = Json.Document(Source),
        items = #"Parsed JSON"[items],
        #"Converted to Table" = Table.FromList(items, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
        #"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"owner"}, {"owner"}),
        #"Expanded owner" = Table.ExpandRecordColumn(#"Expanded Column1", "owner", {"reputation", "user_id", "user_type", "display_name"}, {"reputation", "user_id", "user_type", "display_name"})
    in
        #"Expanded owner"