npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

uban-bi

v0.1.0

Published

适用于 Vue2、eggjs 的 BI 数据处理函数库

Readme

这是一个基于 JS 适用于 Vue2、eggjs 的 npm 包。

命名与编码规范

  • 每个基础 BI 函数采用大驼峰命名,并以 BI 前缀,不超过 20 个字符
  • 尽可能使用纯函数,函数需 JSDoc 注释参数及返回值
  • 每类函数存放在不同文件,并在文件开头写明介绍

安装

npm install uban-bi

依赖:moment、bignumber.js

目录结构

ubanBI/
├── package.json
├── readme.md
├── demo.js                 # 历史参考实现,不再维护
├── design/                 # 设计脑图
│   ├── 表连接-合并.png
│   ├── 表连接-左右连接.png
│   ├── 数据清洗-分组汇总.png
│   └── 数据清洗-格式化.png
├── test/
│   └── test.js             # 烟雾测试,覆盖所有公开函数
└── src/
    ├── index.js            # 统一出口
    ├── utils/              # 内部工具
    │   ├── dfsFuncs.js     # DfsFuncs 类:IF/MAX/MIN/toFixed/toPercent/DateFormat…
    │   ├── stringParser.js # fullMatchReplace, parseBIStr
    │   ├── formula.js      # FormulaFunc, GetValueByPath
    │   ├── evalSafe.js     # getEval, handleValByFuncs
    │   └── filter.js       # MergeFilter, filterDataByPlan
    ├── columns.js          # 新增列类别
    ├── concat.js           # 表连接类别
    ├── clean.js            # 数据清洗类别
    └── contrast.js         # 数据对照

数据结构约定

sourceData = {
  data:   [ { field1: v1, field2: v2, ... }, ... ],   // 行数据
  fields: [ { field: 'field1', name: '显示名', type: 'number|string|...' }, ... ]
}

函数类别 - 新增列

文件:src/columns.js

公式列 BIFormulaFunc

按公式 token 数组逐行计算新列。

/**
 * @param {Object} sourceData { data, fields }
 * @param {Object} options
 * @param {string[]} options.colFields 当前行参与公式的字段名(构建 customDev)
 * @param {Array}   options.formula 公式 token 数组,详见 utils/formula.js
 * @param {Object} [options.globalDev] 全局参数
 * @param {string} options.name 新列显示名
 * @param {string} options.type 新列类型
 * @param {string} options.uuid 新列字段 key
 * @returns {Object[]} data
 */
BIFormulaFunc(sourceData, options)

formula 中每个 token:

  • {type:'X', value:'a'} —— 取当前行 a 字段
  • {type:'GlobalX', value:'g.x'} —— 取 globalDev 的 g.x
  • {type:'ValueX', value:'1'} —— 字面量
  • 字符串元素 —— 运算符(如 '+'、'*')

汇总列 BISumByCols(按列汇总生成新列)

每行将 colFields 多列累加写入新列;非数字按 0 处理。

BISumByCols(sourceData, { colFields, name, type, uuid })

汇总行 BISumByRows(按行汇总生成新行)

对 colFields 中各列纵向累加,追加一行到 data 末尾;不在 colFields 中的列填 null,uuid 字段填 name 作为标识。

BISumByRows(sourceData, { colFields, name, type, uuid })

赋值列 BIAddCol

复制 colFields[0] 到新列,源值为 null / undefined / '' 时赋 defaultValue。

BIAddCol(sourceData, { colFields, defaultValue, name, type, uuid })

条件列 BIAddCondCol

按 filtersList 中第一个匹配的规则赋值,否则赋 defaultValue。

BIAddCondCol(sourceData, {
  filtersList: [
    { filters: 查询方案, value: 命中时赋值, defaultValue?: 该组兜底 },
    ...
  ],
  defaultValue,  // 整体未命中时
  name, type, uuid,
})

查询方案结构:[[rule, ...], ...],外层或、内层并。rule = { key, symbol, value }, symbol 支持 $in | $eq | $ne | $nin | $exists。


函数类别 - 表连接

文件:src/concat.js

BIConcatData 上下连接(纵向)

按 mode 决定输出字段。

BIConcatData(sourceData, { concatArray, mode, fields })
// mode: 'main' | 'over' | 'merge' | 'custom'
//   - main   仅保留主表字段
//   - over   保留所有表都存在的字段(交集)
//   - merge  保留所有表字段并集,缺失填 null(默认)
//   - custom 仅保留 options.fields
// concatArray: [{ data, fields }, ...]
// 返回新的 { data, fields }

设计图:design/表连接-合并.png

BIConcatRow 左右连接(横向)

按 mode 决定连接方式,与 SQL JOIN 同义。

BIConcatRow(sourceData, { concatArray, mode, match })
// mode: 'left' | 'right' | 'inner' | 'outer'(默认 left)
// concatArray: { data, fields } 单表,或 [{ data, fields }] 数组(取首项)
// match: { rule: (l, r) => boolean } 或 { mapKeys: [leftKey, rightKey] }

设计图:design/表连接-左右连接.png


函数类别 - 数据清洗

文件:src/clean.js

分组汇总 BIGroupData

按 groupFields 分组,对 aggFields 执行聚合。

BIGroupData(sourceData, {
  groupFields: ['region', 'product'],
  aggFields: [
    { field: 'sales', agg: 'sum',   alias: 'salesTotal' },
    { field: 'sales', agg: 'avg' },
    { field: 'id',    agg: 'count', alias: 'cnt' },
    { field: 'sales', agg: 'min' },
    { field: 'sales', agg: 'max' },
    { field: 'code',  agg: 'first', alias: 'firstCode' },
    { field: 'code',  agg: 'last',  alias: 'lastCode' },
  ],
})
// agg: 'sum' | 'avg' | 'count' | 'min' | 'max' | 'first' | 'last'
//   - first / last 取分组内首条/末条记录的原值,不做数值转换,保留原类型
// 返回新的 { data, fields }

设计图:design/数据清洗-分组汇总.png

格式转化 BIDataFormat

按 mode 处理字段值。

BIDataFormat(sourceData, {
  mode,         // 'date' | 'datetime' | 'number' | 'toFixed' | 'percent' | 'boolean'
  field,        // 处理的目标字段
  alias,        // 可选,输出字段名(默认覆盖原字段)
  format,       // mode 为 date/datetime 时使用,moment.format 支持的任意值
  dot,          // mode 为 toFixed/percent 时使用,小数位
  trueSign,     // mode 为 boolean 时使用,'是' 返回 是/否;'1' 返回 1/2
})
//   - 'date'     默认 format 为 'YYYY-MM-DD'
//   - 'datetime' 默认 format 为 'YYYY-MM-DD HH:mm:ss'
//   - format 示例:'YYYY/MM' | 'YYYY-MM-DD HH:mm:ss' | 'YYYY年MM月DD日' 等

设计图:design/数据清洗-格式化.png

数据筛选 BIDataFilter

按查询方案筛选。

BIDataFilter(sourceData, filters)
// filters: 查询方案(外层或、内层并)
// 返回新的 { data, fields }

函数类别 - 数据对照

文件:src/contrast.js

handleDataContrast

原始数据按规则与对照表匹配,将对照表字段映射到原始数据。

handleDataContrast(mainData, mapData, {
  fills: [{ source: 'map字段', target: '结果字段' }],
  mode: '11' | 'N1',          // 默认 '11'(一对一);'N1' 为 N 对一
  isAllowNull: false,        // 未匹配是否允许为空(false 抛错)
  uuid: '',                   // 方案 id,用于错误信息
  match: {
    rule: (origItem, mapItem) => boolean,  // 优先使用
    // 或
    mapKeys: ['origKey', 'mapKey'],
  },
})
  • '11':原始数据每条只能匹配一条对照记录,且对照记录不可被重复匹配
  • 'N1':对照表可被多条原始数据匹配

aggregate(占位)

按多步配置对 mainData、auxData 聚合。

aggregate(mainData, auxData, params)

内部工具

文件:src/utils/

| 函数/类 | 文件 | 说明 | |---|---|---| | DfsFuncs | dfsFuncs.js | toBoolean/toNumber/toFixed/toPercent/IF/MAX/MIN/DateStepChange/DateFormat | | fullMatchReplace | stringParser.js | 全匹配替换,转义正则特殊字符 | | parseBIStr | stringParser.js | 递归解析 ${MAX(1,2)} 模板,由内向外求值 | | FormulaFunc | formula.js | 公式求值,支持 X/GlobalX/ValueX token | | GetValueByPath | formula.js | 点分路径取值 | | getEval | evalSafe.js | 受限 eval,禁 this/ctx/service/async | | handleValByFuncs | evalSafe.js | 按函数链转换值 | | MergeFilter | filter.js | 合并公共参数到自定义查询方案 | | filterDataByPlan | filter.js | 按查询方案筛选数据 |


使用示例

const bi = require('uban-bi');

const sourceData = {
  data: [
    { region: 'east', sales: 10, code: 'A' },
    { region: 'east', sales: 20, code: 'B' },
    { region: 'west', sales: 5,  code: 'C' },
  ],
  fields: [
    { field: 'region', name: '区域', type: 'string' },
    { field: 'sales',  name: '销量', type: 'number' },
    { field: 'code',   name: '编码', type: 'string' },
  ],
};

// 1. 公式列:sales + 10
bi.BIFormulaFunc(sourceData, {
  colFields: ['sales'],
  formula: [{ type: 'X', value: 'sales' }, '+', { type: 'ValueX', value: '10' }],
  name: '调整后销量', type: 'number', uuid: 'salesAdj',
});

// 2. 按列汇总
bi.BISumByCols(sourceData, { colFields: ['sales', 'salesAdj'], name: '合计', type: 'number', uuid: 'sum' });

// 3. 分组汇总
const grouped = bi.BIGroupData(sourceData, {
  groupFields: ['region'],
  aggFields: [
    { field: 'sales', agg: 'sum',   alias: 'salesTotal' },
    { field: 'code',  agg: 'first', alias: 'firstCode' },
    { field: 'code',  agg: 'last',  alias: 'lastCode' },
  ],
});

// 4. 日期格式化
bi.BIDataFormat({ data: [{ d: '2024-01-02 03:04:05' }], fields: [] },
  { mode: 'datetime', field: 'd', format: 'YYYY/MM/DD HH:mm' });

// 5. 数据筛选
const filtered = bi.BIDataFilter(sourceData, [[{ key: 'region', symbol: '$eq', value: 'east' }]]);

// 6. 数据对照
const mapped = bi.handleDataContrast(
  [{ code: 'A' }, { code: 'B' }],
  [{ code: 'A', label: '甲' }, { code: 'B', label: '乙' }],
  {
    fills: [{ source: 'label', target: 'label' }],
    match: { mapKeys: ['code', 'code'] },
  },
);

测试

npm test
# 或 node test/test.js

当前覆盖 23 项用例:DfsFuncs、parseBIStr、FormulaFunc、filterDataByPlan、MergeFilter、 BIFormulaFunc、BISumByCols、BISumByRows、BIAddCol、BIAddCondCol、BIConcatData、BIConcatRow、 BIGroupData、BIDataFormat(含 date/datetime 多种 format)、BIDataFilter、handleDataContrast、 getEval、handleValByFuncs、fullMatchReplace。