Skip to content

Instantly share code, notes, and snippets.

@anton-dudarev
Forked from Hugoberry/JSON2table.m
Last active September 5, 2020 11:50
Show Gist options
  • Save anton-dudarev/de5c5f625ae8b1d67c882cede9a36ba1 to your computer and use it in GitHub Desktop.
Save anton-dudarev/de5c5f625ae8b1d67c882cede9a36ba1 to your computer and use it in GitHub Desktop.
JSON to Table in Power Query M
(json) => 
  let
    //List the expandable columns
    expandableColumns = (_) => List.Accumulate(
        Table.ColumnNames(_), 
        {}, 
        (s, c) => 
          s
            & (
            if Type.Is(Value.Type(Record.Field(_{0}, c)), type record)
              or Type.Is(Value.Type(Record.Field(_{0}, c)), type list) then 
              {c}
            else 
              {}
          )
      ),
    // Do the record columns have a consistent structure?
    columnHasConsistentType = (T, Cname) => 
      let
        columnTypes = List.Accumulate(
            Table.Column(T, Cname), 
            {}, 
            (s, c) => s & {Type.RecordFields(Value.Type(c))}
          )
      in
        not (List.Count(List.Distinct(columnTypes)) = List.Count(columnTypes)),
    // Expand the consistent typed column based on their primitive type
    expandConsistentColumn = (T, Cname) => 
      if Table.Column(T, Cname){0} is record then 
        expandRecordColumn(T, Cname)
      else 
        Table.ExpandListColumn(T, Cname),
    // Expand the record column
    expandRecordColumn = (T, Cname) => 
      let
        fields = Record.FieldNames(Table.Column(T, Cname){0})
      in
        Table.ExpandRecordColumn(T, Cname, fields),
    // expand the table column with prefixing the column names with the parent column name
    expandTableColumn = (T, Cname) => Table.ExpandTableColumn(
        Table.TransformColumns(T, {Cname, Record.ToTable}), 
        Cname, 
        {"Name", "Value"}, 
        {Cname & ".Name", Cname & ".Value"}
      ),
    // expand all available columns in the table T
    expand = (T) => List.Accumulate(
        expandableColumns(T), 
        T, 
        (s, c) => 
          if columnHasConsistentType(s, c) then 
            expandConsistentColumn(s, c)
          else 
            expandTableColumn(s, c)
      ),
    // initialize the table structure based on the JSON object
    table_ini = 
      if json is record then 
        Table.FromRecords({json})
      else 
        Table.FromList(json, Splitter.SplitByNothing()),
    // kick off the iteration to expandd all columns form the table based JSON object
    iterator = List.Generate(
        () => [expandable = true, table_chain = table_ini], 
        each [expandable], 
        each [expandable = List.Count(expandableColumns([table_chain])) > 0, table_chain = expand(
            [table_chain]
          )], 
        each [table_chain]
      ),
    // output only the last iteration
    out = List.Last(iterator)
  in
    out
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment