src/operator/group-by.js
function groupBy (dataModel, fieldArr, reducers, existingDataModel) {
    const sFieldArr = getFieldArr(dataModel, fieldArr);
    const reducerObj = getReducerObj(dataModel, reducers);
    const fieldStore = dataModel.getFieldspace();
    const fieldStoreObj = fieldStore.fieldsObj();
    const dbName = fieldStore.name;
    const dimensionArr = [];
    const measureArr = [];
    const schema = [];
    const hashMap = {};
    const data = [];
    let newDataModel;

    // Prepare the schema
    Object.entries(fieldStoreObj).forEach(([key, value]) => {
        if (sFieldArr.indexOf(key) !== -1 || reducerObj[key]) {
            schema.push(extend2({}, value.schema()));

            switch (value.schema().type) {
            case FieldType.MEASURE:
                measureArr.push(key);
                break;
            default:
            case FieldType.DIMENSION:
                dimensionArr.push(key);
            }
        }
    });
    // Prepare the data
    let rowCount = 0;
    rowDiffsetIterator(dataModel._rowDiffset, (i) => {
        let hash = '';
        dimensionArr.forEach((_) => {
            hash = `${hash}-${fieldStoreObj[_].partialField.data[i]}`;
        });
        if (hashMap[hash] === undefined) {
            hashMap[hash] = rowCount;
            data.push({});
            dimensionArr.forEach((_) => {
                data[rowCount][_] = fieldStoreObj[_].partialField.data[i];
            });
            measureArr.forEach((_) => {
                data[rowCount][_] = [fieldStoreObj[_].partialField.data[i]];
            });
            rowCount += 1;
        } else {
            measureArr.forEach((_) => {
                data[hashMap[hash]][_].push(fieldStoreObj[_].partialField.data[i]);
            });
        }
    });

    // reduction
    let cachedStore = {};
    let cloneProvider = () => dataModel.detachedRoot();
    data.forEach((row) => {
        const tuple = row;
        measureArr.forEach((_) => {
            tuple[_] = reducerObj[_](row[_], cloneProvider, cachedStore);
        });
    });
    if (existingDataModel) {
        existingDataModel.__calculateFieldspace();
        newDataModel = existingDataModel;
    }
    else {
        newDataModel = new DataModel(data, schema, { name: dbName });
    }
    return newDataModel;
}
function groupBy (dataModel, fieldArr, reducers, existingDataModel) {
    const sFieldArr = getFieldArr(dataModel, fieldArr);
    const reducerObj = getReducerObj(dataModel, reducers);
    const fieldStore = dataModel.getFieldspace();
    const fieldStoreObj = fieldStore.fieldsObj();
    const dbName = fieldStore.name;
    const dimensionArr = [];
    const measureArr = [];
    const schema = [];
    const hashMap = {};
    const data = [];
    let newDataModel;

    // Prepare the schema
    Object.entries(fieldStoreObj).forEach(([key, value]) => {
        if (sFieldArr.indexOf(key) !== -1 || reducerObj[key]) {
            schema.push(extend2({}, value.schema()));

            switch (value.schema().type) {
            case FieldType.MEASURE:
                measureArr.push(key);
                break;
            default:
            case FieldType.DIMENSION:
                dimensionArr.push(key);
            }
        }
    });
    // Prepare the data
    let rowCount = 0;
    rowDiffsetIterator(dataModel._rowDiffset, (i) => {
        let hash = '';
        dimensionArr.forEach((_) => {
            hash = `${hash}-${fieldStoreObj[_].partialField.data[i]}`;
        });
        if (hashMap[hash] === undefined) {
            hashMap[hash] = rowCount;
            data.push({});
            dimensionArr.forEach((_) => {
                data[rowCount][_] = fieldStoreObj[_].partialField.data[i];
            });
            measureArr.forEach((_) => {
                data[rowCount][_] = [fieldStoreObj[_].partialField.data[i]];
            });
            rowCount += 1;
        } else {
            measureArr.forEach((_) => {
                data[hashMap[hash]][_].push(fieldStoreObj[_].partialField.data[i]);
            });
        }
    });

    // reduction
    let cachedStore = {};
    let cloneProvider = () => dataModel.detachedRoot();
    data.forEach((row) => {
        const tuple = row;
        measureArr.forEach((_) => {
            tuple[_] = reducerObj[_](row[_], cloneProvider, cachedStore);
        });
    });
    if (existingDataModel) {
        existingDataModel.__calculateFieldspace();
        newDataModel = existingDataModel;
    }
    else {
        newDataModel = new DataModel(data, schema, { name: dbName });
    }
    return newDataModel;
}
function groupBy ( dataModel , fieldArr , reducers , existingDataModel ) { const sFieldArr = getFieldArr ( dataModel , fieldArr ) ; const reducerObj = getReducerObj ( dataModel , reducers ) ; const fieldStore = dataModel . getFieldspace ( ) ; const fieldStoreObj = fieldStore . fieldsObj ( ) ; const dbName = fieldStore . name ; const dimensionArr = [ ] ; const measureArr = [ ] ; const schema = [ ] ; const hashMap = { } ; const data = [ ] ; let newDataModel ; // Prepare the schema Object . entries ( fieldStoreObj ) . forEach ( ( [ key , value ] ) => { if ( sFieldArr . indexOf ( key ) !== - 1 || reducerObj [ key ] ) { schema . push ( extend2 ( { } , value . schema ( ) ) ) ; switch ( value . schema ( ) . type ) { case FieldType . MEASURE : measureArr . push ( key ) ; break ; default : case FieldType . DIMENSION : dimensionArr . push ( key ) ; } } } ) ; // Prepare the data let rowCount = 0 ; rowDiffsetIterator ( dataModel . _rowDiffset , ( i ) => { let hash = '' ; dimensionArr . forEach ( ( _ ) => { hash = ` ${ hash } ${ fieldStoreObj [ _ ] . partialField . data [ i ] } ` ; } ) ; if ( hashMap [ hash ] === undefined ) { hashMap [ hash ] = rowCount ; data . push ( { } ) ; dimensionArr . forEach ( ( _ ) => { data [ rowCount ] [ _ ] = fieldStoreObj [ _ ] . partialField . data [ i ] ; } ) ; measureArr . forEach ( ( _ ) => { data [ rowCount ] [ _ ] = [ fieldStoreObj [ _ ] . partialField . data [ i ] ] ; } ) ; rowCount += 1 ; } else { measureArr . forEach ( ( _ ) => { data [ hashMap [ hash ] ] [ _ ] . push ( fieldStoreObj [ _ ] . partialField . data [ i ] ) ; } ) ; } } ) ; // reduction let cachedStore = { } ; let cloneProvider = ( ) => dataModel . detachedRoot ( ) ; data . forEach ( ( row ) => { const tuple = row ; measureArr . forEach ( ( _ ) => { tuple [ _ ] = reducerObj [ _ ] ( row [ _ ] , cloneProvider , cachedStore ) ; } ) ; } ) ; if ( existingDataModel ) { existingDataModel . __calculateFieldspace ( ) ; newDataModel = existingDataModel ; } else { newDataModel = new DataModel ( data , schema , { name : dbName } ) ; } return newDataModel ; }
main function which perform the group-by operations which reduce the measures value is the
fields are common according to the reducer function provided
@param  {DataModel} dataModel the dataModel to worked
@param  {Array} fieldArr  fields according to which the groupby should be worked
@param  {Object|Function} reducers  reducers function
@param {DataModel} existingDataModel Existing datamodel instance
@return {DataModel} new dataModel with the group by
main function which perform the group - by operations which reduce the measures value is the fields are common according to the reducer function provided