• 简体中文
  • havingFilter

    add-having-filter

    按区域分组后筛选销售额超过百万的高业绩区域

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.add('sales', node => { node.setAggregate({"func":"sum"}).setOperator('gt').setValue(1000000); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    add-multiple-having-filter

    链式添加多个Having条件筛选高销售额且高利润的区域

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(1000000)).add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(200000)); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    clear-having-filter

    清空所有Having过滤条件,展示全量分组聚合结果

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": [
                  {
                    "id": "having-1",
                    "field": "sales",
                    "op": "gt",
                    "value": 1000000,
                    "aggregate": {
                      "func": "sum"
                    }
                  },
                  {
                    "id": "having-2",
                    "field": "profit",
                    "op": "gt",
                    "value": 200000,
                    "aggregate": {
                      "func": "sum"
                    }
                  }
                ]
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.clear(); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-array-value-with-in-operator

    Having filter with array value that triggers 'in' operator conversion

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 10
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => {
      builder.havingFilter.add('sales', node => {
        node.setOperator('=').setValue([100, 200, 300]);
      });
    }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-array-value-with-not-in-operator

    Having filter with array value that triggers 'not in' operator conversion

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 10
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => {
      builder.havingFilter.add('sales', node => {
        node.setOperator('!=').setValue([100, 200]);
      });
    }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-clear-and-rebuild

    清除已有having条件后重新构建全新的分组筛选,模拟用户重置筛选面板后重新配置

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "amount",
                  "alias": "数量",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": [
                  {
                    "id": "old-1",
                    "field": "sales",
                    "op": "gt",
                    "value": 999999,
                    "aggregate": {
                      "func": "sum"
                    }
                  }
                ]
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.clear(); builder.havingFilter.addGroup('and', g => { g.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gte').setValue(100000)); g.addGroup('or', sub => { sub.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(20000)); sub.add('amount', n => n.setAggregate({"func":"sum"}).setOperator('gte').setValue(50)); }); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-deeply-nested-groups

    三层嵌套分组:OR(AND(销售额超50万, 利润超5万), AND(数量超100, 折扣均值低于0.3)),模拟复杂业务筛选

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "province",
                  "alias": "省份"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "amount",
                  "alias": "数量",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "discount",
                  "alias": "平均折扣",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "avg"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 10
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.addGroup('or', root => { root.addGroup('and', g1 => { g1.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(500000)); g1.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(50000)); }); root.addGroup('and', g2 => { g2.add('amount', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(100)); g2.add('discount', n => n.setAggregate({"func":"avg"}).setOperator('lt').setValue(0.3)); }); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-empty-dsl-compose-target

    从空DSL出发,通过builder拼装where/having/measures/dimensions,包含sum与countDistinct聚合的having条件组合

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "line",
              "dimensions": [],
              "measures": [],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.chartType.changeChartType('table'); builder.theme.setTheme('light'); builder.locale.setLocale('zh-CN'); builder.whereFilter.add('profit', n => n.setOperator('<').setValue(0)); const whereConds = builder.whereFilter.getConditions(); whereConds.get(0).set('id', 'c84825ed-547a-48f0-b4d9-55ebe53aab8c'); builder.havingFilter.clear(); builder.havingFilter.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('lt').setValue(-100000)); builder.havingFilter.add('province', n => n.setAggregate({"func":"countDistinct"}).setOperator('gt').setValue(4)); const havingConds = builder.havingFilter.getConditions(); havingConds.get(0).set('id', 'a6f2f16a-e0fc-4bdc-9729-bbe3a105cfca'); havingConds.get(1).set('id', '01c004d2-4041-40ee-a18b-a18fc0cea416'); builder.measures.add('sales', n => n.setAlias('sales').setEncoding('yAxis').setAggregate({"func":"sum"})); builder.measures.add('country_or_region', n => n.setAlias('country_or_region').setEncoding('yAxis').setAggregate({"func":"count"})); const measures = builder.dsl.get('measures'); measures.get(0).set('id', 'a5ba6c4a-31dc-4b2c-a38f-9f23c2bbe850'); measures.get(1).set('id', '49f3b33d-4ede-436c-8be9-a51619236916'); builder.dimensions.add('area', n => n.setAlias('area')); const dimensions = builder.dsl.get('dimensions'); dimensions.get(0).set('id', 'c3583433-a2cc-4234-85ff-75ae2472b674'); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-field-not-in-measures-and-dimensions

    初始化空DSL,仅通过builder添加维度area与指标sales,并在having中使用未出现在measures/dimensions里的profit字段(SUM(profit) > 100000)

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "line",
              "dimensions": [],
              "measures": [],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.chartType.changeChartType('bar'); builder.dimensions.add('area', n => n.setAlias('区域')); builder.measures.add('sales', n => n.setAlias('销售额').setEncoding('yAxis').setAggregate({"func":"sum"})); builder.havingFilter.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(100000)); builder.limit.setLimit(20); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-find-and-update

    先添加having条件,然后通过find查找并动态更新阈值和操作符,模拟用户交互式调整筛选条件

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "column",
              "dimensions": [
                {
                  "field": "product_type",
                  "alias": "品类"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(100000)).add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(10000)); const json = builder.havingFilter.toJSON().conditions; const salesId = json[0].id; const profitId = json[1].id; builder.havingFilter.update(salesId, n => { n.setOperator('gte').setValue(500000); }); builder.havingFilter.update(profitId, n => { n.setOperator('gte').setValue(50000); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-group-add-to-existing

    向已有的having分组中追加新条件,模拟用户逐步细化筛选规则

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "amount",
                  "alias": "数量",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": [
                  {
                    "id": "group-1",
                    "op": "or",
                    "conditions": [
                      {
                        "id": "cond-1",
                        "field": "sales",
                        "op": "gt",
                        "value": 500000,
                        "aggregate": {
                          "func": "sum"
                        }
                      }
                    ]
                  }
                ]
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.updateGroup('group-1', group => { group.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(100000)); group.add('amount', n => n.setAggregate({"func":"sum"}).setOperator('gte').setValue(200)); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-group-remove-condition

    从已有的having分组中移除特定条件,模拟用户取消某个筛选项

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "column",
              "dimensions": [
                {
                  "field": "product_type",
                  "alias": "品类"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": [
                  {
                    "id": "group-1",
                    "op": "and",
                    "conditions": [
                      {
                        "id": "cond-1",
                        "field": "sales",
                        "op": "gt",
                        "value": 100000,
                        "aggregate": {
                          "func": "sum"
                        }
                      },
                      {
                        "id": "cond-2",
                        "field": "profit",
                        "op": "gt",
                        "value": 10000,
                        "aggregate": {
                          "func": "sum"
                        }
                      }
                    ]
                  }
                ]
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.updateGroup('group-1', group => { group.remove('cond-1'); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-mix-filters-and-groups

    混合使用独立过滤条件和OR分组:销售额超50万 AND (利润超10万 OR 数量不少于30)

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "amount",
                  "alias": "数量",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(500000)).addGroup('or', group => { group.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(100000)); group.add('amount', n => n.setAggregate({"func":"sum"}).setOperator('gte').setValue(30)); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-multi-dimension-aggregate

    按品类和区域双维度分组,筛选平均折扣低于20%且总销售额超过10万的组合,分析高价值低折扣业务

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "product_type",
                  "alias": "品类",
                  "sort": {
                    "order": "asc"
                  }
                },
                {
                  "field": "area",
                  "alias": "区域",
                  "sort": {
                    "order": "asc"
                  }
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "discount",
                  "alias": "平均折扣",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "avg"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 10
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.addGroup('and', g => { g.add('discount', n => n.setAggregate({"func":"avg"}).setOperator('lt').setValue(0.2)); g.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(100000)); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-nested-groups

    嵌套分组:AND(销售额超100万, OR(利润超20万, 数量不少于50))

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "amount",
                  "alias": "数量",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.addGroup('and', outer => { outer.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(1000000)); outer.addGroup('or', inner => { inner.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(200000)); inner.add('amount', n => n.setAggregate({"func":"sum"}).setOperator('gte').setValue(50)); }); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-or-group

    使用OR分组筛选高销售额或高利润的区域

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.addGroup('or', group => { group.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(1000000)); group.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(200000)); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-scatter-profit-analysis

    散点图分析:按品类分组筛选高利润率且交易量超20笔的品类,定位优质业务

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "scatter",
              "dimensions": [
                {
                  "field": "product_sub_type",
                  "alias": "子品类"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "xAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "amount",
                  "alias": "数量",
                  "encoding": "size",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 10
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.addGroup('and', g => { g.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(0)); g.add('amount', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(20)); g.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(10000)); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-update-group-operator

    更新已有Having分组的逻辑操作符从AND改为OR

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": [
                  {
                    "id": "group-1",
                    "op": "and",
                    "conditions": [
                      {
                        "id": "cond-1",
                        "field": "sales",
                        "op": "gt",
                        "value": 1000000,
                        "aggregate": {
                          "func": "sum"
                        }
                      },
                      {
                        "id": "cond-2",
                        "field": "profit",
                        "op": "gt",
                        "value": 200000,
                        "aggregate": {
                          "func": "sum"
                        }
                      }
                    ]
                  }
                ]
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.updateGroup('group-1', group => { group.setOperator('or'); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    having-with-where-combined

    where与having联合筛选:先按where筛选办公用品品类,再按having筛选销售额超5万或利润超1万的省份

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "column",
              "dimensions": [
                {
                  "field": "province",
                  "alias": "省份"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 10
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.whereFilter.add('product_type', n => n.setOperator('=').setValue('办公用品')); builder.havingFilter.addGroup('or', g => { g.add('sales', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(50000)); g.add('profit', n => n.setAggregate({"func":"sum"}).setOperator('gt').setValue(10000)); }); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }

    remove-having-filter

    移除多余的Having过滤条件,只保留利润筛选

    Loading...
    import { VBI, VBIChartBuilder } from '@visactor/vbi'
    import { DEMO_CONNECTOR_ID, VSeedRender } from '@components'
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [result, setResult] = useState<any>(null)
    
      useEffect(() => {
        const run = async () => {
          const builder = VBI.chart.create({
            ...{
              "connectorId": "demoSupermarket",
              "chartType": "bar",
              "dimensions": [
                {
                  "field": "area",
                  "alias": "区域"
                }
              ],
              "measures": [
                {
                  "field": "sales",
                  "alias": "销售额",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                },
                {
                  "field": "profit",
                  "alias": "利润",
                  "encoding": "yAxis",
                  "aggregate": {
                    "func": "sum"
                  }
                }
              ],
              "whereFilter": {
                "id": "root",
                "op": "and",
                "conditions": []
              },
              "havingFilter": {
                "id": "root",
                "op": "and",
                "conditions": [
                  {
                    "id": "having-1",
                    "field": "sales",
                    "op": "gt",
                    "value": 1000000,
                    "aggregate": {
                      "func": "sum"
                    }
                  },
                  {
                    "id": "having-2",
                    "field": "profit",
                    "op": "gt",
                    "value": 200000,
                    "aggregate": {
                      "func": "sum"
                    }
                  }
                ]
              },
              "theme": "light",
              "locale": "zh-CN",
              "version": 1,
              "limit": 20
            },
            connectorId: DEMO_CONNECTOR_ID,
          })
          const applyBuilder = (builder: VBIChartBuilder) => { builder.havingFilter.remove('having-1'); }
          await applyBuilder(builder)
          setResult(await builder.buildVSeed())
        }
        run()
      }, [])
    
      if (!result) return <div>Loading...</div>
    
      return <VSeedRender vseed={result} />
    }