Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Slate의 행과 열 스키마 변환

행 지향 데이터는 객체들의 배열이며 열 지향 데이터는 열 이름마다 값 배열을 가진 객체입니다. Slate의 SQL 질의 결과나 표 변수는 열 지향 구성을 사용하고, Handlebars의 each 반복 등에는 행 배열이 편할 수 있습니다.

다음 예제 입력을 기준으로 두 표현을 비교합니다.

[
  {"foo":1,"bar":4,"baz":7},
  {"bar":5,"baz":8,"foo":2},
  {"foo":3,"baz":9,"bar":6}
]

같은 데이터의 열 지향 표현은 다음과 같습니다.

{"foo":[1,2,3],"bar":[4,5,6],"baz":[7,8,9]}

행에서 열로

transformRowSchemaToColumnSchema의 첫 입력은 행 객체 배열입니다. first_object_has_all_keys의 기본값은 true이며 첫 행에 추출할 모든 열 이름이 있어야 합니다. false로 호출하면 모든 행의 키 합집합을 사용합니다.

function transformRowSchemaToColumnSchema(rows, first_object_has_all_keys) {
  if (first_object_has_all_keys === undefined) {
    first_object_has_all_keys = true;
  }
  var columns = Object.create(null);
  if (rows.length === 0) return columns;

  var keys;
  var rowIndex;
  var keyIndex;
  if (first_object_has_all_keys) {
    keys = Object.keys(rows[0]).sort();
  } else {
    keys = [];
    var seen = Object.create(null);
    for (rowIndex = 0; rowIndex < rows.length; rowIndex++) {
      var rowKeys = Object.keys(rows[rowIndex]);
      for (keyIndex = 0; keyIndex < rowKeys.length; keyIndex++) {
        var key = rowKeys[keyIndex];
        if (seen[key] !== true) {
          seen[key] = true;
          keys.push(key);
        }
      }
    }
  }

  for (keyIndex = 0; keyIndex < keys.length; keyIndex++) {
    var columnKey = keys[keyIndex];
    var values = new Array(rows.length);
    for (rowIndex = 0; rowIndex < rows.length; rowIndex++) {
      values[rowIndex] = Object.prototype.hasOwnProperty.call(rows[rowIndex], columnKey)
        ? rows[rowIndex][columnKey]
        : undefined;
    }
    columns[columnKey] = values;
  }
  return columns;
}

첫 행 기준 모드는 키를 문자열 순서로 준비하고, 합집합 모드는 각 행에서 처음 만난 키 순서를 사용합니다. 결과값은 키로 대응하므로 객체의 키 열거 순서에 의존하지 않습니다. 첫 행의 키만 사용하는 모드에서 이후 행에 새 키가 있으면 그 열은 포함하지 않으므로, 그런 입력에는 false를 사용합니다.

빈 행 배열은 빈 열 객체 {}가 됩니다. 어떤 행에 해당 속성이 없으면 그 셀은 undefined입니다.

Slate 함수에서 사용하려면 위 정의를 함수 본문에 넣고 마지막에 다음을 추가합니다. f_data는 행 배열을 반환하는 입력 함수의 이름으로 바꿀 수 있습니다.

var data = {{f_data}};
return transformRowSchemaToColumnSchema(data);

열에서 행으로

transformColumnSchemaToRowSchema는 각 데이터 열이 배열인 객체를 입력받습니다. 기본 호출은 모든 열을 유지합니다. SQL 질의 응답의 메타데이터인 _response를 제외하려면 두 번째 인자 skipResponseMetadata를 true로 지정합니다. 이 경우 열 목록을 만들기 전에 메타데이터를 제외하며 입력 객체 자체는 수정하지 않습니다.

function transformColumnSchemaToRowSchema(data, skipResponseMetadata) {
  var inputKeys = Object.keys(data);
  var keys = [];
  var rowCount = 0;
  var i;
  for (i = 0; i < inputKeys.length; i++) {
    var key = inputKeys[i];
    if (skipResponseMetadata && key === "_response") continue;
    if (!Array.isArray(data[key])) {
      throw new TypeError("Column must be an array: " + key);
    }
    keys.push(key);
    if (data[key].length > rowCount) rowCount = data[key].length;
  }

  var rows = new Array(rowCount);
  for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) {
    var row = Object.create(null);
    for (i = 0; i < keys.length; i++) {
      row[keys[i]] = data[keys[i]][rowIndex];
    }
    rows[rowIndex] = row;
  }
  return rows;
}

데이터 열이 없으면 빈 행 배열을 반환합니다. 열 길이가 서로 다르면 가장 긴 열을 기준으로 행을 만들고 짧은 열의 부족한 값은 undefined가 됩니다. 배열이 아닌 데이터 열은 오류로 처리합니다. Slate의 Table 변수 편집기는 모든 열 길이가 같아야 하므로 그 입력을 만들 때에는 길이도 맞춥니다.

Slate 함수 본문에서 위 정의 다음에 연결합니다.

var data = {{f_data}};
return transformColumnSchemaToRowSchema(data);

SQL 응답 메타데이터가 포함된 입력에는 transformColumnSchemaToRowSchema(data, true)를 사용합니다. _response가 실제 데이터 열인 일반 입력에는 기본 호출을 유지합니다.

두 변환은 셀의 객체값을 깊게 복제하지 않습니다. undefined는 JSON 값이 아니므로 직렬화할 때도 구분해야 합니다. 배열 원소의 undefined는 null이 되고 객체 속성의 undefined는 해당 속성이 생략됩니다. 결측값을 JSON으로 유지해야 한다면 사용하는 데이터 계약에 맞춰 값을 정합니다.