API
API
Classes
PivotCube

PivotCube

Properties

columns: Array (opens in a new tab)<ColumnMeta> readonly

컬럼 메타데이터 배열을 반환한다.

default: undefined

listenerCount: number (opens in a new tab) readonly

등록된 리스너 개수를 반환한다.

default: undefined

name: string (opens in a new tab)

default: undefined

rowCount: number (opens in a new tab) readonly

필터 적용된 행 개수를 반환한다.
addFilter(), filterAll(), applySlicers() 등으로 설정된 필터를 반영한다.
필터가 없으면 전체 행 수(totalRowCount)와 동일한 값을 반환한다.

default: undefined

See Also

  • totalRowCount 원본 전체 행 개수
  • addFilter 필터 추가
  • filterAll 필터 일괄 적용

schema: CubeSchema readonly

큐브 스키마를 반환한다.

default: undefined

source: CubeDataSource readonly

큐브 데이터 소스를 반환한다.
ColumnStore 또는 DataViewSource 인스턴스일 수 있다.

default: undefined

table: DataTable readonly

default: undefined

totalRowCount: number (opens in a new tab) readonly

필터와 무관한 원본 전체 행 개수를 반환한다.

default: undefined

See Also

rowCount 필터 적용 후 행 개수

Methods

addExpressionFilter(name, expression): void (opens in a new tab)

수식 기반 필터를 추가한다.

ParameterTypeDescription
namestring (opens in a new tab)필터 이름 (고유해야 함)
expressionstring (opens in a new tab)필터 수식 (예: 'sales > 1000 AND profit > 100')

addFilter(filter): void (opens in a new tab)

단일 필터를 추가하거나 업데이트한다.
CubeFilter 형식의 필터를 추가한다. 같은 dimension 필터가 있으면 대체된다.

ParameterTypeDescription
filterCubeFilter추가할 CubeFilter

addListener(listener): void (opens in a new tab)

이벤트 리스너를 추가한다.

ParameterTypeDescription
listenerany (opens in a new tab)이벤트 리스너

addMeasure(name, options): this

동적 계산 측정값(calculated measure)을 DataCube에 등록한다.
등록된 측정값은 aggregate()에서 이름으로 참조할 수 있다.

이 메서드는 row-level 계산을 정의한다.
각 행에서 계산된 값을 지정된 집계 함수(aggregate)로 집계한다.

Row-level 계산

  • 각 데이터 행에서 먼저 값을 계산
  • 계산된 값들을 aggregate로 집계 (sum, avg, min, max, count)
// Expression string 사용
cube.addMeasure('margin', { source: 'profit / sales * 100', aggregate: 'avg' });
cube.addMeasure('total_revenue', { source: 'price * quantity', aggregate: 'sum' });
 
// 함수 사용
cube.addMeasure('margin_pct', {
  source: (row) => row.sales > 0 ? (row.profit / row.sales * 100) : 0,
  aggregate: 'avg'
});
 
// aggregate에서 이름으로 참조
const agg = cube.aggregate(['region'], ['sales', 'margin', 'total_revenue']);
ParameterTypeDescription
namestring (opens in a new tab)측정값 이름 (고유해야 함)
options{ aggregate: 'sum' &#124; 'avg' &#124; 'min' &#124; 'max' &#124; 'count' &#124; 'distinct' &#124; 'product' &#124; 'stdev' &#124; 'stdevp' &#124; 'var' &#124; 'varp' &#124; 'first' &#124; 'last' &#124; 'p25' &#124; 'p50' &#124; 'p75';source: string &#124; (row: any) => any;type: 'i32' &#124; 'f64' &#124; 'str' &#124; 'date'; }옵션 객체
  • source: 계산 수식(expression 문자열) 또는 계산 함수 (필수)
  • 문자열: 'profit / sales * 100' 같은 expression
  • 함수: (row: any) => row.profit / row.sales * 100
  • aggregate: 집계 함수 (기본값: 'sum')
  • type: 결과 타입 'f64' | 'i32' (기본값: 'f64') |

return this (메서드 체이닝 가능)

addMetric(name, expression): this

집계 후 계산할 지표(metric)을 DataCube에 등록한다.
이미 집계된 다른 measure들의 값으로부터 계산되는 post-aggregate 지표이다.

Metric은 반드시 적어도 하나의 차원을 가지고 있어야 하며, 차원이 없는 전체 집계에서는 계산되지 않는다.

Row-level Measure vs Metric

  • Measure: 각 row에서 계산 후 집계
    • 예: profit / qty (각 row에서 계산)
  • Metric: 집계 후 계산
    • 예: profit / sales * 100 (sum(profit) / sum(sales) * 100)
// Measure 등록
cube.addMeasure('profit', { source: 'profit', aggregate: 'sum' });
cube.addMeasure('sales', { source: 'sales', aggregate: 'sum' });
cube.addMeasure('qty', { source: 'qty', aggregate: 'sum' });
 
// Metric 등록
cube.addMetric('profit_margin', 'profit / sales * 100');
cube.addMetric('profit_per_qty', 'profit / qty');
 
// aggregate에서 함께 사용
const agg = cube.aggregate(['region'], [
  'profit',           // Measure
  'sales',            // Measure
  'profit_margin',    // Metric (자동으로 차원 필요)
  'profit_per_qty'    // Metric
]);
ParameterTypeDescription
namestring (opens in a new tab)지표 이름 (고유해야 함)
expressionstring (opens in a new tab)계산 수식 (다른 measure 이름 참조)
  • 예: 'profit / sales * 100'
  • 참조 가능: 등록된 모든 measure와 다른 metric |

return this (메서드 체이닝 가능)

addSlicer(options): Slicer

Slicer를 추가한다.

const slicer = cube.addSlicer({ name: 'region', dimension: 'region' });
slicer.select(['Seoul', 'Busan']);
cube.applySlicers();
ParameterTypeDescription
optionsSlicerOptionsSlicer 옵션 (name 필수)

return 생성된 Slicer 인스턴스

aggregate(dimensionNames, measureNames?, options?): AggTable

지정된 차원과 측정값으로 집계 테이블을 생성한다.

일반 차트(막대, 선, 파이 등)는 이 메서드로 충분하며, 피벗 테이블(crosstab)이 필요한 경우에만 pivot()을 사용한다.

디자인 타임 vs 런타임

  • mutable: false (기본값): 불변 AggTable 생성, 캐시 가능
    • 런타임용, 프로덕션 차트에 최적
    • 동일 조합 요청 시 캐시된 인스턴스 재사용
  • mutable: true: 가변 AggTable 생성, 캐시 불가
    • 디자인 타임용, 차트 설정 중 차원/측정값 변경 가능
    • 확정 후 freeze() 호출 필요

Aggregate 오버라이드

Schema에 정의된 기본 aggregate를 특정 AggTable에서만 변경할 수 있다.

Metric과의 관계:

  • Metric(post-aggregate 지표)은 집계된 measure 값을 참조하여 계산됨
  • aggregate 오버라이드 시, 해당 AggTable 내의 metric도 오버라이드된 집계값을 사용
  • 예: profit_rate = profit / sales * 100에서 sales를 avg로 오버라이드하면, profit_rate는 profit(sum) / sales(avg) * 100으로 계산됨
  • 각 AggTable은 독립적이므로, 다른 AggTable의 metric 계산에는 영향 없음

집계 결과 구조

  • Dimension 컬럼: 그룹화 기준이 되는 차원들의 고유 조합
  • Measure 컬럼: 각 그룹별로 집계된 측정값 (sum, avg, min, max, count)
  • Metric 컬럼: 집계된 measure를 기반으로 계산된 지표
// 동적 측정값 등록
cube.addMeasure('margin', { source: 'profit / sales * 100', aggregate: 'avg' });
 
// 런타임: immutable AggTable (캐시됨)
const agg1 = cube.aggregate(['region'], ['sales', 'margin']);
const agg2 = cube.aggregate(['region'], ['sales', 'margin']); // 캐시에서 재사용 ✓
 
// 디자인 타임: mutable AggTable (캐시 안됨)
const draft = cube.aggregate(['region'], ['sales'], { mutable: true });
draft.addDimension(productCol);    // 차원 추가
draft.removeMeasure('quantity');   // 측정값 제거
draft.freeze();                    // 확정 → 이후 캐시 가능
 
// aggregate 오버라이드: 기본 sum → avg로 변경
// metric (profit_rate)도 오버라이드된 sales(avg) 값을 사용
const aggAvg = cube.aggregate(['region'], ['sales', 'profit_rate'], {
    aggregates: { sales: 'avg' }
});
// sales: avg로 집계
// profit_rate = profit(sum) / sales(avg) * 100  ← 오버라이드된 값 사용
 
// 다중 오버라이드
const aggMulti = cube.aggregate(['region'], ['sales', 'quantity', 'avg_price'], {
    aggregates: { sales: 'avg', quantity: 'max' }
});
// avg_price = sales(avg) / quantity(max)
ParameterTypeDescription
dimensionNamesArray (opens in a new tab)<string (opens in a new tab)>집계할 차원 이름 배열 (예: ['region', 'product'])
measureNamesArray (opens in a new tab)<string (opens in a new tab) | MeasureAlias>집계할 측정값/지표 이름 배열 (생략 시 스키마의 모든 측정값 사용).
measure와 metric을 함께 지정 가능.
options{ aggregates: Record<string, CubeAggregateType>;filters: Array<CubeFilter>;force: boolean;mutable: boolean;userKey: string; }집계 옵션

return 집계 결과 테이블 (AggTable)

aggregateAll(): AggTable

모든 차원과 모든 측정값을 사용하여 집계를 수행한다.
내부적으로 aggregate()를 호출하여 전체 데이터에 대한 집계 테이블을 생성한다.

동작 방식

  1. 스키마에서 모든 차원(dimension)을 조회한다.
  2. 스키마에서 모든 측정값(measure)과 메트릭(metric)을 조회한다.
  3. aggregate(allDimensions, allMeasuresAndMetrics)를 호출한다.
// 스키마: dimensions = ['region', 'product'], measures = ['sales', 'quantity']
const agg = cube.aggregateAll();
// 동일: cube.aggregate(['region', 'product'], ['sales', 'quantity'])

return 모든 차원으로 그룹화하고 모든 측정값을 집계한 불변 AggTable

applySlicers(): void (opens in a new tab)

등록된 모든 Slicer의 활성 필터를 수집하여 DataCube에 일괄 적용한다.
내부적으로 filterAll()을 호출한다.

// 개별 변경: select()가 자동으로 applySlicers() 호출
cube.getSlicer('region')?.select(['Seoul']);
 
// 배치 변경: apply=false로 지연 후 직접 호출
cube.getSlicer('region')?.select(['Seoul'], false);
cube.getSlicer('category')?.select('Electronics', false);
cube.applySlicers();  // 한 번만 filterAll() 호출

beginUpdate(): void (opens in a new tab)

이벤트 발생을 일시적으로 중단한다.
beginUpdate()와 endUpdate()는 중첩 호출을 지원한다. endUpdate() 호출 횟수가 beginUpdate() 호출 횟수와 같아지면 이벤트 발생이 재개된다.

중요: 예외 발생 시에도 endUpdate()가 반드시 호출되도록 try-finally 패턴을 사용해야 한다.

table.beginUpdate();
try {
    table.setValue(0, 0, 'value1');
    table.setValue(0, 1, 'value2');
    table.updateRow(1, ['a', 'b', 'c']);
    // ... 여러 작업들
} finally {
    table.endUpdate();
}

canDimension(name): boolean (opens in a new tab)

ParameterType
namestring (opens in a new tab)

canMeasure(name): boolean (opens in a new tab)

ParameterType
namestring (opens in a new tab)

clearCache(): void (opens in a new tab)

캐시된 모든 집계 테이블과 피벗 매트릭스를 제거한다.
메모리를 확보하거나 데이터 변경 후 재계산이 필요할 때 사용한다.

clearFilters(): void (opens in a new tab)

모든 필터를 제거한다 (API 필터 + Slicer 필터 모두).

clearListeners(): void (opens in a new tab)

모든 이벤트 리스너를 제거한다.

dice(filters): DataCube

지정된 차원의 특정 범위로 데이터를 다이싱한다.
여러 차원에 대한 필터 조건을 동시에 적용하여 부분 큐브를 생성하는 OLAP 다이싱 연산이다.
슬라이싱(slice)은 단일 차원을 필터링하는 반면, 다이싱(dice)은 다중 차원을 한 번에 필터링한다.

동작 방식

  1. 필터 맵의 각 차원별 조건을 검증한다.
  2. 모든 필터 조건을 AND로 결합하여 적용한다.
  3. 필터링된 데이터를 새로운 DataTableView로 래핑한다.
  4. 래핑된 뷰를 DataViewSource로 변환한다.
  5. 새로운 DataCube 인스턴스를 생성하여 반환한다.

slice()와의 차이점

기능slice()dice()
필터 개수1개 차원여러 차원
호출 방식단일 호출단일 호출
적용 방식순차적 (체이닝 필요)동시 적용
사용 사례단계별 드릴다운한번에 다중 조건

필터 조건 형식

필터 맵의 각 값은 다음 두 가지 형식을 지원한다:

1. 정확한 값 필터 (Exact Match)

{ region: 'Seoul', quarter: 'Q1' }
// region == 'Seoul' AND quarter == 'Q1'

2. 범위 필터 (Range)

{ sales: [1000, 5000] }  // 1000 <= sales <= 5000
{ quantity: [0, 100] }   // 0 <= quantity <= 100

성능 고려사항

  • 장점: 여러 조건을 한 번에 적용하므로 필터링 비용 최소화
  • 비용: 모든 필터 조건을 각 행에서 평가해야 함
  • 권장: 3개 이상의 차원 필터가 필요한 경우 dice() 사용
// 기본 사용: 다중 정확한 값 필터
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// Seoul 지역, Q1 분기의 데이터만 추출
const dicedCube = cube.dice(
  new Map([
    ['region', 'Seoul'],
    ['quarter', 'Q1']
  ])
);
 
// 결과: region == 'Seoul' AND quarter == 'Q1'인 행만 포함
const agg = dicedCube.aggregate(['product'], ['sales']);
// 범위 필터 사용: 매출액 범위 제한
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 매출이 10,000 ~ 50,000 범위인 데이터만
const dicedCube = cube.dice(
  new Map([
    ['sales', [10000, 50000]]  // 10000 <= sales <= 50000
  ])
);
 
// 결과: 매출 범위에 해당하는 행만 포함
const agg = dicedCube.aggregate(['region'], ['quantity']);
// 혼합 필터: 정확한 값 + 범위 필터
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// Seoul 지역 + Q1 분기 + 판매량 50~100
const dicedCube = cube.dice(
  new Map([
    ['region', 'Seoul'],           // 정확한 값
    ['quarter', 'Q1'],             // 정확한 값
    ['quantity', [50, 100]]        // 범위 필터
  ])
);
 
// 결과: 모든 조건을 만족하는 행만 포함
const agg = dicedCube.aggregate(['product'], ['sales']);
// 복잡한 다중 조건 필터
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 여러 지역 + 가격대 + 시간 범위 조합
const dicedCube = cube.dice(
  new Map([
    ['region', 'Seoul'],          // 특정 지역
    ['product', 'A'],             // 특정 제품
    ['price', [1000, 5000]],      // 가격대
    ['date', ['2024-01-01', '2024-03-31']]  // 날짜 범위
  ])
);
 
// 모든 조건을 만족하는 상세 분석
const pivot = dicedCube.pivot(
  ['region', 'product'],
  ['quarter'],
  'sales'
);
// 빈 필터 맵 (필터링 없음)
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 필터 없이 전체 데이터
const dicedCube = cube.dice(new Map()); // 또는 new Map([])
 
// 원본 큐브와 동일한 결과
const agg1 = cube.aggregate(['region'], ['sales']);
const agg2 = dicedCube.aggregate(['region'], ['sales']);
// agg1과 agg2는 동일한 결과
// slice()와의 비교
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 방법 1: slice() 체이닝 (3번의 호출)
const result1 = cube
  .slice('region', 'Seoul')
  .slice('quarter', 'Q1')
  .slice('product', 'A')
  .aggregate(['date'], ['sales']);
 
// 방법 2: dice() 단일 호출
const result2 = cube
  .dice(new Map([
    ['region', 'Seoul'],
    ['quarter', 'Q1'],
    ['product', 'A']
  ]))
  .aggregate(['date'], ['sales']);
 
// 두 결과는 동일하지만 dice()가 더 효율적
// Excel pivot 스타일: 다중 필터와 피벗을 한 번에
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// Seoul 지역 + Q1 분기의 제품x날짜 피벗을 한 번에 생성
const pivot = cube.dice(
  new Map([
    ['region', 'Seoul'],
    ['quarter', 'Q1']
  ]),
  ['product'],    // 행 차원
  ['date'],       // 열 차원
  'sales'         // 측정값
);
 
// 결과는 PivotMatrix
console.log(pivot.rowLabels);    // [['A'], ['B']]
console.log(pivot.columnLabels); // [['2024-01-01'], ['2024-01-02'], ...]
ParameterTypeDescription
filtersMap (opens in a new tab)<string (opens in a new tab), any (opens in a new tab)>차원별 필터 조건 맵
키: 차원 이름 (string (opens in a new tab))
값: 필터 값 (any) 또는 범위 [최소값, 최대값]
빈 맵은 필터링 없음 (전체 데이터)

return 다이싱된 새로운 DataCube 인스턴스

원본 큐브의 데이터 소스와 동일한 스키마를 가지며,
지정된 모든 조건을 만족하는 데이터만 포함

See Also

  • slice 단일 차원 필터링
  • drillDown 계층적 드릴다운
  • aggregate 다이싱된 데이터 집계
  • pivot 다이싱된 데이터 피벗

dispose(): null

객체를 해제하고 null을 반환한다.
사용 예: this._obj = this._obj.dispose();

return null

drillDown(fromDimension, toDimension): AggTable

차원 계층을 따라 드릴다운한다.
상위 차원에서 하위 차원으로 세부 수준을 낮춰 분석하는 OLAP 연산이다.
상위 수준의 요약 데이터에서 세부 수준으로 분해하며, 롤업의 역 연산이다.

ParameterTypeDescription
fromDimensionstring (opens in a new tab)현재(상위) 차원 이름
toDimensionstring (opens in a new tab)드릴다운할 하위 차원 이름

return 드릴다운된 집계 테이블

endUpdate(): void (opens in a new tab)

이벤트 발생을 재개한다.
beginUpdate() 호출 횟수만큼 endUpdate()를 호출해야 이벤트 발생이 재개된다.

중요: try-finally 블록의 finally에서 호출하여 예외 발생 시에도 실행되도록 해야 한다.

filter(expressionString): DataCube

Expression을 사용하여 필터링한다.
@realgrid/expression 라이브러리를 사용하여 복잡한 필터 조건을 적용한다.

지원하는 연산자

  • 비교: >, >=, <, <=, ==, !=
  • 논리: AND, OR, NOT
  • 문자열: CONTAINS, STARTSWITH, ENDSWITH
  • IN: IN (value1, value2, ...)
  • 범위: BETWEEN min AND max
  • NULL: IS NULL, IS NOT NULL
// 단순 비교
const cube1 = cube.filter('sales > 1000');
const cube2 = cube.filter('region == "Seoul"');
 
// 논리 연산
const cube3 = cube.filter('sales > 1000 AND region == "Seoul"');
const cube4 = cube.filter('product == "A" OR product == "B"');
 
// IN 연산자
const cube5 = cube.filter('region IN ("Seoul", "Busan", "Daegu")');
 
// 범위 필터
const cube6 = cube.filter('sales BETWEEN 1000 AND 5000');
 
// 문자열 패턴
const cube7 = cube.filter('productName CONTAINS "Phone"');
const cube8 = cube.filter('productCode STARTSWITH "P-"');
 
// NULL 체크
const cube9 = cube.filter('discount IS NOT NULL');
 
// 복잡한 조합
const cube10 = cube.filter(
  '(region == "Seoul" OR region == "Busan") AND sales > 1000'
);
ParameterTypeDescription
expressionStringstring (opens in a new tab)Expression 문자열

return 필터링된 새로운 DataCube

filterAll(filters): void (opens in a new tab)

여러 Slicer 필터를 일괄 적용한다.
각 필터를 현재 큐브의 _filters Map에 저장하고, 등록된 AggTable 리스너들에게 알림을 보낸다.

// 직접 사용 (현재 큐브가 변경됨)
cube.filterAll([
  { dimension: 'region', type: 'list', values: ['Seoul', 'Busan'] },
  { dimension: 'sales', type: 'range', range: [1000, 5000] }
]);
 
// 필터 초기화
cube.filterAll([]);
ParameterTypeDescription
filtersArray (opens in a new tab)<CubeFilter>적용할 CubeFilter 배열

See Also

  • slice 단일 차원 필터링 (새 DataCube 반환, immutable)
  • dice 다중 차원 필터링 (새 DataCube 반환, immutable)

filterHierarchical(dimensionName, paths): DataCube

계층적 필터링을 수행한다.
날짜(year/month/day)같은 계층 구조에서 상위 수준을 선택하면 하위 수준이 자동으로 포함된다.

// year/month/day 계층의 경우
// 2024년만 필터 → 2024년의 모든 월, 일 자동 포함
cube.filterHierarchical('order_date', [2024])
 
// 명시적으로 특정 월만 선택
cube.filterHierarchical('order_date', [['2024', '01'], ['2024', '02']])
 
// 여러 연도의 특정 월
cube.filterHierarchical('order_date', [
  ['2024', '01'],
  ['2025', '01']
])
ParameterTypeDescription
dimensionNamestring (opens in a new tab)계층 구조가 있는 차원 이름 (e.g., 'order_date')
pathsArray (opens in a new tab)<any (opens in a new tab)>포함할 경로 배열
  • 단일 값 배열: [2024, '01', '15'] 또는 [2024, '01']
  • 이중 배열: [[2024, '01'], [2024, '02']] |

return 필터링된 새로운 DataCube 인스턴스

getActiveSlicerFilters(): Array (opens in a new tab)<CubeFilter>

활성화된 Slicer 필터 목록을 반환한다.

getApiFilters(): Map (opens in a new tab)<string (opens in a new tab), any (opens in a new tab)>

API 필터만 반환한다.

getCardinalities(): Record (opens in a new tab)<string (opens in a new tab), number (opens in a new tab)>

모든 차원의 카디날리티(고유값 개수)를 한 번에 반환한다.

피벗 UI에서 row/column 필드 배치 가능 여부를 판단할 때 유용하다.
카디날리티가 높은 차원을 축에 배치하면 UI 폭발이 발생할 수 있다.

const cards = cube.getCardinalities();
// { region: 3, product: 5, quarter: 2, customer_id: 100000 }
 
// 카디날리티 100 이하인 차원만 피벗 축에 배치 가능
const pivotableDims = Object.entries(cards)
    .filter(([_, card]) => card <= 100)
    .map(([name]) => name);
// ['region', 'product', 'quarter']

return 차원 이름을 키로, 카디날리티를 값으로 하는 객체

getCardinality(dimensionName): number (opens in a new tab)

지정된 차원의 카디날리티(고유값 개수)를 반환한다.

Dictionary Encoding된 컬럼은 O(1)로 즉시 반환하며, 그렇지 않은 경우 전체 컬럼을 순회하여 계산한다.

주의: 필터가 적용된 경우에도 전체 데이터의 카디날리티를 반환한다. 필터링된 데이터의 카디날리티가 필요하면 getColumnValues(name).length를 사용한다.

const cube = new DataCube({source, schema});
 
// 지역 차원의 카디날리티
const regionCount = cube.getCardinality('region');  // 4 (O(1) - Dictionary 활용)
 
// 전체 차원의 카디날리티 확인
cube.schema.dimensions.forEach(dim => {
    console.log(`${dim.name}: ${cube.getCardinality(dim.name)}`);
});
ParameterTypeDescription
dimensionNamestring (opens in a new tab)차원 이름

return 고유값 개수

getChildDimensions(dimensionName): Array (opens in a new tab)<string (opens in a new tab)>

지정된 차원의 자식 차원들을 반환한다.
계층 관계를 탐색할 때 사용한다.

cube.getChildDimensions('order_date.year'); // ['order_date.month']
cube.getChildDimensions('order_date.month'); // ['order_date.day']
ParameterTypeDescription
dimensionNamestring (opens in a new tab)차원 이름

return 자식 차원 이름 배열

getColumn(column): ColumnMeta

ParameterType
columnstring (opens in a new tab)

getColumnType(column): CubeColumnDataType

ParameterType
columnstring (opens in a new tab)

getColumnValues(columnName, filtered?): Array (opens in a new tab)<any (opens in a new tab)>

컬럼의 고유값 목록을 리턴한다.
dimension, measure 구분 없이 모든 컬럼에 대해 사용 가능하다.

반환값 특성

  • 중복 제거된 고유값만 포함
  • null/undefined 값은 필터링됨
  • 정렬: 숫자는 오름차순, 문자는 사전순
  • 원본 데이터 타입 유지
// 원본 전체 고유값
const regions = cube.getColumnValues('region');
 
// 필터 적용된 고유값
const filtered = cube.getColumnValues('region', true);
ParameterTypeDescription
columnNamestring (opens in a new tab)컬럼 이름
filteredboolean (opens in a new tab)true이면 slicer 필터가 적용된 데이터에서 추출, false(기본)이면 원본 전체에서 추출

return 고유값 배열 (정렬됨), 컬럼이 없으면 undefined

getDimensionRange(dimensionName): { max: any;min: any; }

지정된 차원의 수치 범위(최소값, 최대값)를 반환한다.
필터가 적용되어 있으면 필터링된 데이터 범위 내에서의 min/max를 반환한다.
수치형 차원에서만 의미있는 값을 반환하며, 문자형 차원에서는 null을 반환한다.

용도

  • 범위 필터 UI의 슬라이더 최소/최대값 설정
  • 데이터 분포 확인 (최소값, 최대값)
  • 차트의 축(axis) 범위 설정
  • 동적 범위 검증

반환값 특성

필터 적용

  • 현재 큐브에 적용된 필터가 있으면 자동으로 반영
  • 필터링된 데이터 범위 내에서만 min/max를 계산
const cube = new DataCube({source, schema});
 
// 판매량의 범위 확인
const salesRange = cube.getDimensionRange('sales');
// 반환: { min: 100, max: 50000 }
 
// 슬라이더 UI 구성
const range = cube.getDimensionRange('quantity');
if (range) {
    setupSlider({
        min: range.min,
        max: range.max,
        step: 10
    });
}
 
// 필터 후 범위 확인
const filtered = cube.slice('region', 'Seoul');
const seoulRange = filtered.getDimensionRange('sales');
// 반환: Seoul 지역의 판매량 범위
ParameterTypeDescription
dimensionNamestring (opens in a new tab)차원 이름 (수치형이어야 함)

return 범위 객체 {min: number (opens in a new tab), max: number (opens in a new tab)} 또는 null

- 수치형 차원: 범위 객체
- 문자형/날짜형 차원: null
- 빈 데이터: null

getDimensions(): Array<{ name: string;parentDimension: string;type: string; }>

큐브의 모든 차원(dimension) 정보를 반환한다.
각 차원의 이름, 타입, 상위 차원(parentDimension) 정보를 포함한다.
UI에서 계층 구조를 표시할 때 사용한다.

const dimensions = cube.getDimensions();
// [
//   { name: 'order_date.year', type: 'i32', parentDimension: undefined },
//   { name: 'order_date.month', type: 'str', parentDimension: 'order_date.year' },
//   { name: 'order_date.day', type: 'str', parentDimension: 'order_date.month' },
//   { name: 'region', type: 'str', parentDimension: undefined }
// ]

return 차원 정보 배열

getFilters(): Map (opens in a new tab)<string (opens in a new tab), any (opens in a new tab)>

현재 적용된 필터들을 반환한다 (API + Slicer 병합).

return 필터 맵 (필터명/dimension → 값/수식)

getMeasure(name): MeasureMeta

ParameterType
namestring (opens in a new tab)

getMeasures(): Array (opens in a new tab)<MeasureMeta>

현재 등록된 모든 measure 목록을 반환한다.

const measures = cube.getMeasures();
console.log(measures.map(m => m.name));  // ['sales', 'quantity', 'cost']

return measure 필드 목록

getMeasuresAndMetrics(): Array<{ aggregate: string;name: string;role: 'measure' &#124; 'metric';source: string &#124; (row: any) => any;type: 'i32' &#124; 'f64' &#124; 'i64' &#124; 'str' &#124; 'date'; }>

현재 등록된 모든 measure와 metric 목록을 반환한다.
UI에서 동적으로 필드 목록을 관리할 때 유용하다.

const fields = cube.getMeasuresAndMetrics();
// [
//   { name: 'sales', type: 'f64', role: 'measure', aggregate: 'sum', source: 'sales' },
//   { name: 'quantity', type: 'i32', role: 'measure', aggregate: 'sum', source: 'qty' },
//   { name: 'margin', type: 'f64', role: 'metric', source: 'profit / sales * 100' },
// ]
 
// UI에서 드롭다운 구성
const options = fields.map(f => ({ label: f.name, value: f.name }));

return measure와 metric 필드 목록
- name: 필드 이름
- type: 필드 타입 ('f64', 'i32')
- role: 'measure' 또는 'metric'
- aggregate?: measure의 경우 집계 함수 (metric은 undefined)
- source?: expression 또는 source 컬럼명

getMemoryUsage(): { aggTables: number;source: number;total: number; }

큐브의 메모리 사용량 정보를 반환한다.

큐브가 사용 중인 전체 메모리를 세 부분으로 나누어 추정한다:

  • source: 원본 데이터(ColumnStore/DataViewSource)의 메모리
  • aggTables: 캐시된 집계 테이블들의 총 메모리
  • pivotMatrices: 캐시된 피벗 매트릭스들의 총 메모리

메모리 추정 방식

1. 데이터 소스 메모리 (source)

데이터 소스의 메모리는 각 컬럼의 데이터 타입을 기반으로 추정된다:

  • 숫자형 (i32, f64): 행 개수 × 바이트/값
    • i32: 4바이트/값
    • f64: 8바이트/값
  • 문자열 (str): 행 개수 × (평균 문자열 길이 × 2 + 메타데이터)
    • 평균 문자열 길이 추정: 50자
    • 메타데이터 오버헤드: 16바이트/값
  • 객체 오버헤드: 약 1KB

2. 집계 테이블 메모리 (aggTables)

각 캐시된 AggTable의 메모리는 차원 컬럼과 측정값 컬럼의 합으로 계산된다:

  • 행 개수 × (컬럼별 바이트 크기)
  • AggTable 객체 오버헤드: 약 2KB

예시:

차원 2개 (문자열) + 측정값 3개 (숫자)
100행의 경우:
- 문자열 차원: 100 × (30 × 2 + 16) × 2 = 15,200바이트
- 숫자 측정값: 100 × 8 × 3 = 2,400바이트
- 오버헤드: 2,048바이트
- 합계: 약 19.6KB

3. 피벗 매트릭스 메모리 (pivotMatrices)

피벗 매트릭스의 메모리는 레이블과 셀 데이터로 구성된다:

  • 행 레이블: 행 개수 × 레이블당 평균 바이트
  • 열 레이블: 열 개수 × 레이블당 평균 바이트
  • 셀 데이터: 행 개수 × 열 개수 × 8바이트 (Float64Array)
  • 객체 오버헤드: 약 2KB

예시:

5행(지역) × 4열(분기)의 피벗:
- 행 레이블: 5 × (10 × 2 + 16) = 180바이트
- 열 레이블: 4 × (5 × 2 + 16) = 104바이트
- 셀 데이터: 5 × 4 × 8 = 160바이트
- 오버헤드: 2,048바이트
- 합계: 약 2.5KB

메모리 최적화 팁

1. 불필요한 캐시 제거

const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 여러 집계 작업 수행
const agg1 = cube.aggregate(['region'], ['sales']);
const agg2 = cube.aggregate(['product'], ['sales']);
const agg3 = cube.aggregate(['date'], ['sales']);
 
// 캐시 메모리 확인
const usage = cube.getMemoryUsage();
console.log(`전체 메모리: ${(usage.total / 1024 / 1024).toFixed(2)}MB`);
 
// 캐시 제거하여 메모리 절약
cube.clearCache();
const usageAfter = cube.getMemoryUsage();
console.log(`캐시 제거 후: ${(usageAfter.total / 1024 / 1024).toFixed(2)}MB`);

2. 데이터 소스 크기 최소화

// 방법 1: DataViewSource 사용 (복사 없음)
const viewSource = new DataViewSource(columns, dataView);
cube1.setSource(viewSource);  // 메모리 효율적
 
// 방법 2: ColumnStore 사용 (복사 + 최적화)
const columnStore = new ColumnStore(columns, dataFrame);
cube2.setSource(columnStore);  // 더 많은 메모리 사용

3. 필터링으로 데이터 크기 줄이기

const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 전체 메모리
const fullUsage = cube.getMemoryUsage();
console.log(`전체: ${fullUsage.total}바이트`);
 
// 필터링된 큐브 (더 적은 메모리)
const filtered = cube.slice('region', 'Seoul');
const filteredUsage = filtered.getMemoryUsage();
console.log(`필터링: ${filteredUsage.total}바이트`);

메모리 모니터링 예시

const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 초기 메모리
console.log('=== 메모리 사용량 ===');
let usage = cube.getMemoryUsage();
console.log(`소스: ${(usage.source / 1024).toFixed(2)}KB`);
console.log(`집계: ${(usage.aggTables / 1024).toFixed(2)}KB`);
console.log(`피벗: ${(usage.pivotMatrices / 1024).toFixed(2)}KB`);
console.log(`총계: ${(usage.total / 1024).toFixed(2)}KB`);
 
// 집계 추가
cube.aggregate(['region'], ['sales']);
usage = cube.getMemoryUsage();
console.log(`
n집계 후: ${(usage.total / 1024).toFixed(2)}KB`);
 
// 피벗 추가
cube.pivot(['region'], ['quarter'], 'sales');
usage = cube.getMemoryUsage();
console.log(`피벗 후: ${(usage.total / 1024).toFixed(2)}KB`);

주의사항

  • 메모리 사용량은 추정값이며 JavaScript 엔진의 최적화에 따라 실제 값과 다를 수 있다.
  • 문자열 길이는 평균값(50자, 30자)으로 추정되므로 실제 데이터와 차이가 날 수 있다.
  • 동적으로 캐시가 추가될 때마다 메모리 사용량이 증가한다.
  • 대용량 데이터의 경우 정기적으로 clearCache()를 호출하여 메모리를 관리하는 것을 권장한다.
// 기본 사용
const cube = new DataCube();
cube.setSource(dataViewSource);
 
const usage = cube.getMemoryUsage();
console.log(`메모리 사용량: ${usage.total} 바이트`);
console.log(`소스: ${usage.source} 바이트`);
console.log(`집계: ${usage.aggTables} 바이트`);
console.log(`피벗: ${usage.pivotMatrices} 바이트`);
// 메모리 단위 변환
const cube = new DataCube();
cube.setSource(dataViewSource);
 
const usage = cube.getMemoryUsage();
 
// 바이트 → KB
const totalKB = usage.total / 1024;
console.log(`총 메모리: ${totalKB.toFixed(2)}KB`);
 
// 바이트 → MB
const totalMB = usage.total / 1024 / 1024;
console.log(`총 메모리: ${totalMB.toFixed(2)}MB`);
// 메모리 성장 추적
const cube = new DataCube();
cube.setSource(dataViewSource);
 
const memoryLog: { step: string; memory: number }[] = [];
 
// 초기 상태
memoryLog.push({
  step: '초기',
  memory: cube.getMemoryUsage().total
});
 
// 첫 번째 집계
cube.aggregate(['region'], ['sales']);
memoryLog.push({
  step: '집계1(region)',
  memory: cube.getMemoryUsage().total
});
 
// 두 번째 집계
cube.aggregate(['product'], ['sales']);
memoryLog.push({
  step: '집계2(product)',
  memory: cube.getMemoryUsage().total
});
 
// 피벗
cube.pivot(['region'], ['product'], 'sales');
memoryLog.push({
  step: '피벗(region×product)',
  memory: cube.getMemoryUsage().total
});
 
// 메모리 성장 확인
for (const log of memoryLog) {
  console.log(`${log.step}: ${(log.memory / 1024).toFixed(2)}KB`);
}
// 메모리 상한선 모니터링
const cube = new DataCube();
cube.setSource(dataViewSource);
 
const MAX_MEMORY_MB = 100; // 100MB 상한선
 
// 여러 집계 작업
const dimensions = [
  ['region'],
  ['product'],
  ['quarter'],
  ['region', 'product'],
  ['product', 'quarter'],
  ['region', 'quarter']
];
 
for (const dims of dimensions) {
  cube.aggregate(dims, ['sales', 'quantity']);
 
  const usage = cube.getMemoryUsage();
  const usageMB = usage.total / 1024 / 1024;
 
  console.log(`${dims.join('×')}: ${usageMB.toFixed(2)}MB`);
 
  // 상한선 초과 시 캐시 제거
  if (usageMB > MAX_MEMORY_MB) {
    console.log('경고: 메모리 상한선 초과! 캐시를 제거합니다.');
    cube.clearCache();
  }
}

return 메모리 사용량 정보 객체 (단위: 바이트)

- source: 원본 데이터 소스 메모리
- aggTables: 캐시된 집계 테이블 메모리 (모든 테이블의 합)
- pivotMatrices: 캐시된 피벗 매트릭스 메모리 (모든 매트릭스의 합)
- total: 전체 메모리 (source + aggTables + pivotMatrices)

See Also

  • clearCache 캐시 제거하여 메모리 해제
  • aggregate 집계 테이블 생성
  • pivot 피벗 매트릭스 생성

getMetrics(): Array (opens in a new tab)<ColumnMeta>

현재 등록된 모든 metric 목록을 반환한다.

const metrics = cube.getMetrics();
console.log(metrics.map(m => m.name));  // ['profit_margin', 'roi']

return metric 필드 목록

getParentDimension(dimensionName): string (opens in a new tab)

지정된 차원의 상위 차원을 반환한다.
계층 관계를 탐색할 때 사용한다.

cube.getParentDimension('order_date.month'); // 'order_date.year'
cube.getParentDimension('order_date.year');  // undefined
ParameterTypeDescription
dimensionNamestring (opens in a new tab)차원 이름

return 상위 차원 이름 또는 undefined

getRow(row, filtered?): Array (opens in a new tab)<any (opens in a new tab)>

지정한 행의 값을 큐브 컬럼(dimensions + measures) 순서로 반환한다.
원본 데이터소스의 전체 필드가 아닌, 큐브 스키마에 정의된 컬럼들만 포함한다.
수식 컬럼(expression source)의 계산된 값도 포함된다.
metric 컬럼은 집계 후 계산되는 파생값이므로 데이터소스에 존재하지 않아 undefined를 반환한다.

ParameterTypeDescription
rownumber (opens in a new tab)행 인덱스
filteredboolean (opens in a new tab)true이면 필터 적용된 데이터에서 조회, false이면 원본 전체 데이터에서 조회 (기본값: true)

return 큐브 컬럼 순서의 값 배열. 범위를 벗어나면 undefined

getRows(start?, count?, filtered?): Array (opens in a new tab)<Array (opens in a new tab)<any (opens in a new tab)>>

지정한 범위의 행들을 큐브 컬럼(dimensions + measures) 순서로 반환한다.
원본 데이터소스의 전체 필드가 아닌, 큐브 스키마에 정의된 컬럼들만 포함한다.
수식 컬럼(expression source)의 계산된 값도 포함된다.
metric 컬럼은 집계 후 계산되는 파생값이므로 데이터소스에 존재하지 않아 undefined를 반환한다.

ParameterTypeDescription
startnumber (opens in a new tab)시작 행 인덱스 (기본값: 0)
countnumber (opens in a new tab)가져올 행 수 (기본값: 전체)
filteredboolean (opens in a new tab)true이면 필터 적용된 데이터에서 조회, false이면 원본 전체 데이터에서 조회 (기본값: true)

return 행 배열. 범위를 벗어나면 빈 배열

getSchema(): { dimensions: Array<DimensionMeta>;measures: Array<MeasureMeta>;metrics: Array<ColumnMeta>; }

현재 DataCube의 전체 스키마 정보를 반환한다.
addMeasure/addMetric으로 동적으로 추가된 필드도 포함한다.

cube.addMeasure('custom_cost', { source: 'cost * qty' });
cube.addMetric('custom_roi', 'profit / investment');
 
const schema = cube.getSchema();
// {
//   dimensions: [{ name: 'region', type: 'str' }, ...],
//   measures: [
//     { name: 'sales', type: 'f64', aggregate: 'sum' },
//     { name: 'custom_cost', type: 'f64', aggregate: 'sum' }, // 동적 추가됨
//     ...
//   ],
//   metrics: [
//     { name: 'margin', source: 'profit / sales * 100', type: 'f64' },
//     { name: 'custom_roi', source: '...' }, // 동적 추가됨
//     ...
//   ]
// }

return 스키마 정보 객체
- dimensions: 모든 차원 필드 목록
- measures: 모든 measure 필드 목록 (동적 추가된 measure 포함)
- metrics: 모든 metric 필드 목록

getSlicer(name): Slicer

Slicer를 가져온다.

ParameterTypeDescription
namestring (opens in a new tab)Slicer 이름

getSlicerFilters(): Map (opens in a new tab)<string (opens in a new tab), any (opens in a new tab)>

Slicer 필터만 반환한다.

getSlicers(): Map (opens in a new tab)<string (opens in a new tab), Slicer>

모든 Slicer를 가져온다.

getSourceRowIndex(row, filtered?): number (opens in a new tab)

행 인덱스에 대응하는 원본 소스의 행 인덱스를 반환한다.
filtered=true이면 필터 적용된 뷰 기준, false이면 원본 소스 기준으로 매핑한다.
필터가 없으면 동일한 인덱스를 반환한다.

ParameterTypeDescription
rownumber (opens in a new tab)행 인덱스
filteredboolean (opens in a new tab)true이면 필터 적용된 데이터 기준, false이면 원본 전체 데이터 기준 (기본값: true)

return 원본 소스의 행 인덱스. 범위를 벗어나면 -1

getSourceRowIndices(start?, count?, filtered?): Array (opens in a new tab)<number (opens in a new tab)>

행 인덱스 범위에 대응하는 원본 소스의 행 인덱스 배열을 반환한다.
filtered=true이면 필터 적용된 뷰 기준, false이면 원본 소스 기준으로 매핑한다.
필터가 없으면 start부터 순차적인 인덱스 배열을 반환한다.

ParameterTypeDescription
startnumber (opens in a new tab)시작 행 인덱스 (기본값: 0)
countnumber (opens in a new tab)가져올 행 수 (기본값: 전체)
filteredboolean (opens in a new tab)true이면 필터 적용된 데이터 기준, false이면 원본 전체 데이터 기준 (기본값: true)

return 원본 소스의 행 인덱스 배열. 범위를 벗어나면 빈 배열

getValue(row, col, filtered?): any (opens in a new tab)

지정한 행과 컬럼의 단일 값을 반환한다.
원본 데이터소스의 전체 필드가 아닌, 큐브 스키마에 정의된 컬럼 기준으로 조회한다.
metric 컬럼은 집계 후 계산되는 파생값이므로 데이터소스에 존재하지 않아 undefined를 반환한다.

ParameterTypeDescription
rownumber (opens in a new tab)행 인덱스
colstring (opens in a new tab) | number (opens in a new tab)큐브 컬럼 인덱스 또는 컬럼 이름
filteredboolean (opens in a new tab)true이면 필터 적용된 데이터에서 조회, false이면 원본 전체 데이터에서 조회 (기본값: true)

return 셀 값. 범위를 벗어나면 undefined

hasColumn(name): boolean (opens in a new tab)

지정된 이름이 DataCube에 존재하는지 검사한다.

ParameterType
namestring (opens in a new tab)

isMetric(name): boolean (opens in a new tab)

ParameterType
namestring (opens in a new tab)

isUpdating(): boolean (opens in a new tab)

현재 이벤트 발생이 중단된 상태인지 확인한다.

return 이벤트 발생이 중단된 상태이면 true, 그렇지 않으면 false

off(eventName, handler): boolean (opens in a new tab)

특정 이벤트에서 핸들러를 제거한다.

const handler = (sender, row) => console.log(row);
table.on('onRowUpdated', handler);
table.off('onRowUpdated', handler);
ParameterTypeDescription
eventNamenever이벤트 이름
handlerany (opens in a new tab)제거할 이벤트 핸들러 함수

return 제거 성공 여부

on(eventName, handler): void (opens in a new tab)

특정 이벤트에 핸들러를 등록한다.
addEventListener()보다 간편한 방식으로 개별 이벤트 핸들러를 등록할 수 있다.

table.on('onRowUpdated', (sender, row, oldValues) => {
    console.log('Row updated:', row);
});
ParameterTypeDescription
eventNamenever이벤트 이름
handlerany (opens in a new tab)이벤트 핸들러 함수

onChange(callback): () => void (opens in a new tab)

필터 변경 콜백을 등록한다.
addFilter(), removeFilter(), filterAll() 등으로 필터가 변경될 때 호출된다.
반환된 함수를 호출하면 콜백이 해제된다.

const unsub = cube.onChange(() => {
    console.log('filters changed:', cube.getFilters());
});
// 해제
unsub();
ParameterTypeDescription
callback() => void필터 변경 시 호출될 콜백 함수

return 콜백 해제 함수

refreshSlicers(): void (opens in a new tab)

모든 Slicer를 새로고침한다.

registerListener(listener): void (opens in a new tab)

ParameterType
listenerany (opens in a new tab)

removeFilter(name): void (opens in a new tab)

필터를 제거한다.
API 필터에서 제거한다. Slicer 필터에서도 해당 키를 찾아 제거한다.

ParameterTypeDescription
namestring (opens in a new tab)제거할 필터명 (dimension 이름 또는 expression 필터 이름)

removeListener(listener): boolean (opens in a new tab)

이벤트 리스너를 제거한다.

ParameterTypeDescription
listenerany (opens in a new tab)이벤트 리스너

return 제거 성공 여부

removeMeasure(name): this

등록된 measure를 제거한다.
measure 제거 후 관련 캐시는 자동으로 무효화된다.

cube.removeMeasure('old_measure');
cube.removeMeasure('cost')
    .removeMeasure('expense');
ParameterTypeDescription
namestring (opens in a new tab)제거할 measure 이름

return this (메서드 체이닝 가능)

removeMetric(name): this

등록된 metric을 제거한다.
metric 제거 후 관련 캐시는 자동으로 무효화된다.

cube.removeMetric('profit_margin');
cube.removeMetric('roi')
    .removeMetric('margin_pct');
ParameterTypeDescription
namestring (opens in a new tab)제거할 metric 이름

return this (메서드 체이닝 가능)

removeSlicer(name): boolean (opens in a new tab)

Slicer를 제거한다.

ParameterTypeDescription
namestring (opens in a new tab)제거할 Slicer 이름

return 제거 성공 여부

resetSlicers(): void (opens in a new tab)

모든 Slicer를 초기화한다.

resetUpdate(): void (opens in a new tab)

이벤트 락 카운터를 강제로 0으로 리셋한다.

경고: 이 메서드는 예외 처리 누락 등으로 인해 이벤트 락이 영구적으로 걸린 경우에만 사용해야 한다. 정상적인 흐름에서는 beginUpdate()/endUpdate()를 올바르게 사용해야 한다.

// 디버깅이나 에러 복구 시
if (table.isUpdating()) {
    console.warn('Event lock is stuck, resetting...');
    table.resetUpdate();
}

restoreSlicerState(state): void (opens in a new tab)

저장된 Slicer 상태를 복원한다.

ParameterTypeDescription
stateRecord (opens in a new tab)<string (opens in a new tab), any (opens in a new tab)>saveSlicerState()로 저장한 상태 객체

rollUp(fromDimension, toDimension): AggTable

차원 계층을 따라 롤업한다.
하위 차원에서 상위 차원으로 세부 수준을 높여 요약하는 OLAP 연산이다.
상세한 데이터를 더 높은 수준의 집계로 변환하며, 드릴다운의 역 연산이다.

개념

롤업(Roll-up)은 세부 차원에서 상위 차원으로 이동하면서 데이터를 요약하는 OLAP 연산이다.
예를 들어, 일(Day) 단위의 상세 데이터를 월(Month)로 요약하거나,
월(Month)의 데이터를 분기(Quarter)로 요약하는 방식으로 동작한다.

계층 구조 예시

시간 계층:          조직 계층:              지역 계층:
년도                회사                   국가
 ↑                   ↑                      ↑
 분기               부서                   대륙
 ↑                   ↑                      ↑
 월                 팀                     국가
 ↑                   ↑                      ↑
 일                 개인                   지역

롤업 방향: 아래에서 위로 (세부 → 요약)

동작 방식

  1. fromDimension에서 현재 집계된 데이터 조회
  2. toDimension이 fromDimension의 상위 계층임을 확인
  3. fromDimension의 각 행을 toDimension으로 매핑
  4. 동일한 상위 차원 값을 가진 행들을 집계
  5. 측정값을 해당 집계 함수로 병합 (합계, 평균 등)
  6. 롤업된 결과를 AggTable로 반환

drillDown()과의 비교

기능drillDown()rollUp()
방향위 → 아래아래 → 위
차원 이동상위 → 하위하위 → 상위
세부도증가 (세부화)감소 (요약)
행 개수증가감소
측정값분해/조회병합/요약
사용 사례상세 분석 드릴다운상위 수준 보고서 생성

계층 검증 규칙

// 유효한 롤업 (fromDimension이 toDimension의 하위 계층)
rollUp('date', 'month')      // 일 → 월 ✓
rollUp('month', 'quarter')   // 월 → 분기 ✓
rollUp('quarter', 'year')    // 분기 → 연도 ✓
 
// 무효한 롤업
rollUp('month', 'date')      // 상위 → 하위 ✗ (드릴다운이어야 함)
rollUp('date', 'date')       // 동일 차원 ✗
rollUp('date', 'region')     // 관계없는 차원 ✗ (계층 관계 없음)

측정값 병합 전략

// 날짜별 판매량 데이터
2024-01-01: 100 판매량
2024-01-02: 150 판매량
2024-01-03: 120 판매량
 
// 월로 롤업 시 (Sum 집계)
2024-01: 370 판매량 (100+150+120)
 
// 월로 롤업 시 (Average 집계)
2024-01: 123.33 판매량 (평균값)

성능 고려사항

  • 비용: 하위 차원의 모든 행을 읽고 상위 차원으로 그룹화
  • 최적화: 이미 하위 차원 집계가 있으면 재사용 가능
  • 메모리: 결과 행 개수가 현저히 감소하므로 메모리 효율적
  • 권장: 대시보드 요약이나 경영진 보고서 생성 시 활용
// 기본 사용: 일 → 월로 롤업
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 먼저 일별로 집계
const dayAgg = cube.aggregate(['date'], ['sales', 'quantity']);
// 결과: 2024-01-01, 2024-01-02, 2024-01-03, ... (상세)
 
// 월로 롤업하여 요약
const monthAgg = cube.rollUp('date', 'month');
// 결과: 2024-01, 2024-02, ... (요약)
// 다단계 롤업: 일 → 월 → 분기 → 연도
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// Step 1: 일별 판매 데이터
const dayData = cube.aggregate(['date'], ['sales']);
 
// Step 2: 월로 롤업
const monthData = cube.rollUp('date', 'month');
 
// Step 3: 분기로 롤업
const quarterData = cube.rollUp('month', 'quarter');
 
// Step 4: 연도로 롤업 (최상위 요약)
const yearData = cube.rollUp('quarter', 'year');
// 결과: 2024년의 총합 1건 (가장 요약된 형태)
// 조직 계층 롤업: 개인 → 팀 → 부서 → 회사
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 직원별 목표 달성률
const employeePerf = cube.aggregate(['employee'], ['target', 'actual']);
// 결과: 100명의 직원 데이터
 
// 팀 단위로 롤업 (평균 달성률)
const teamPerf = cube.rollUp('employee', 'team');
// 결과: 10개 팀의 평균 성과
 
// 부서 단위로 롤업
const deptPerf = cube.rollUp('team', 'department');
// 결과: 3개 부서의 평균 성과
 
// 회사 전체 성과
const companyPerf = cube.rollUp('department', 'company');
// 결과: 회사 전체 1개 행 (최종 요약)
// 지역 계층 롤업: 지점 → 지역 → 대구역 → 전국
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 지점별 매출
const storeData = cube.aggregate(['store'], ['sales']);
// 결과: 50개 지점
 
// 지역 단위로 롤업
const regionData = cube.rollUp('store', 'region');
// 결과: 8개 지역
 
// 대구역 단위로 롤업
const areaData = cube.rollUp('region', 'largeArea');
// 결과: 3개 대구역 (서부, 중부, 동부)
 
// 전국 단위 (최종)
const nationalData = cube.rollUp('largeArea', 'country');
// 결과: 전국 1개 행
// drillDown()과의 비교
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 연도 데이터에서 시작
const yearData = cube.aggregate(['year'], ['sales']);
// 2024년 총 매출: 1,000,000
 
// 방법 1: drillDown으로 분기 단위로 드릴다운
const quarterData = cube.drillDown('year', 'quarter');
// Q1: 200,000 / Q2: 300,000 / Q3: 250,000 / Q4: 250,000
 
// 방법 2: 분기에서 다시 month로 드릴다운
const monthData = cube.drillDown('quarter', 'month');
// Jan: 50,000 / Feb: 60,000 / ...
 
// 역방향: rollUp으로 월에서 분기로 롤업
const backToQuarter = cube.rollUp('month', 'quarter');
// Q1: 200,000 (다시 집계)
// 피벗과 함께 사용
const cube = new DataCube();
cube.setSource(dataViewSource);
 
// 일별 제품별 판매 데이터
const dailyData = cube.aggregate(['date', 'product'], ['sales']);
 
// 월로 롤업하여 월별 제품별 판매
const monthlyByProduct = cube.rollUp('date', 'month')
  .then(agg => {
    // 월별 제품별 피벗 생성
    return cube.pivot(['month'], ['product'], 'sales');
  });
 
// 결과: 월(행) x 제품(열) 의 크로스탭
// 형태: 12행 (월) x 5열 (제품) 매트릭스
ParameterTypeDescription
fromDimensionstring (opens in a new tab)현재(하위) 차원 이름
세부 수준의 차원 (예: 'date', 'month')
toDimensionstring (opens in a new tab)롤업할 상위 차원 이름
더 높은 수준의 차원 (예: 'month', 'year')
fromDimension의 상위 계층이어야 함

return 롤업된 집계 테이블

toDimension 차원으로 그룹화된 데이터, 행 개수 감소

See Also

  • drillDown 역 연산 - 상위에서 하위로 드릴다운
  • aggregate 기본 집계 연산
  • pivot 롤업 결과의 피벗 처리

saveSlicerState(): Record (opens in a new tab)<string (opens in a new tab), any (opens in a new tab)>

Slicer 상태를 JSON으로 저장한다.

slice(dimensionName, value): DataCube

ParameterType
dimensionNamestring (opens in a new tab)
valueany (opens in a new tab)

unregisterListener(listener): void (opens in a new tab)

ParameterType
listenerany (opens in a new tab)

updateFilter(name, value): void (opens in a new tab)

필터 값을 업데이트한다.

ParameterTypeDescription
namestring (opens in a new tab)필터명 (dimension 이름 또는 expression 필터 이름)
valueany (opens in a new tab)새로운 값 또는 수식

updateMeasure(name, options?): this

등록된 measure를 수정한다.
measure의 source, aggregate, type 등을 변경할 수 있다.
필드명 변경은 불가능하며 (removeMeasure + addMeasure 사용), source나 aggregate 변경 시에만 캐시가 초기화된다.

// 집계 함수 변경
cube.updateMeasure('sales', { aggregate: 'avg' });
 
// Source 변경
cube.updateMeasure('cost', { source: 'actual_cost * rate' });
 
// 타입 변경
cube.updateMeasure('count', { type: 'i32' });
 
// 여러 속성 동시 변경
cube.updateMeasure('total', {
    source: 'amount * quantity',
    aggregate: 'sum',
    type: 'f64'
});
ParameterTypeDescription
namestring (opens in a new tab)수정할 measure 이름
options{ aggregate: 'sum' &#124; 'avg' &#124; 'min' &#124; 'max' &#124; 'count' &#124; 'distinct' &#124; 'product' &#124; 'stdev' &#124; 'stdevp' &#124; 'var' &#124; 'varp' &#124; 'first' &#124; 'last' &#124; 'p25' &#124; 'p50' &#124; 'p75';source: string &#124; (row: any) => any;type: 'i32' &#124; 'f64'; }수정할 옵션
  • source?: 새로운 source (컬럼명 또는 계산식)
  • aggregate?: 새로운 집계 함수
  • type?: 새로운 타입 ('f64' | 'i32') |

return this (메서드 체이닝 가능)

updateMetric(name, expression): this

등록된 metric을 수정한다.
metric의 계산식을 변경할 수 있다.
계산식 변경 시 캐시가 초기화된다.

// 계산식 수정 (버그 수정)
cube.updateMetric('margin', 'profit / sales * 100');
 
// 다른 measure 참조로 변경
cube.updateMetric('ratio', 'revenue / cost');
 
// 메서드 체이닝
cube.updateMetric('m1', 'a + b')
    .updateMetric('m2', 'a * b');
ParameterTypeDescription
namestring (opens in a new tab)수정할 metric 이름
expressionstring (opens in a new tab)새로운 계산식 (measure/metric 이름 참조)

return this (메서드 체이닝 가능)

static generateAggregateKey(dimensionNames, measureColumns, userKey?): string (opens in a new tab)

집계 캐시 키를 생성한다.
차원과 측정값 조합을 문자열로 표현하여 캐시 키로 사용한다.
userKey가 주어지면 동일한 차원/측정값 조합이라도 논리적으로 분리된 캐시 키를 생성한다.

ParameterTypeDescription
dimensionNamesArray (opens in a new tab)<string (opens in a new tab)>차원 이름 배열
measureColumnsArray (opens in a new tab)<ColumnMeta>측정값 컬럼 메타데이터 배열
userKeystring (opens in a new tab)(선택) 캐시를 논리적으로 분리하기 위한 사용자 지정 키

return 캐시 키 (형식: agg[@userKey]:dim1|dim2|...:measure1:aggregate1|measure2:aggregate2|...)