明凯博客

关注网站技术,一个特立独行的程序员

Superset Filter box报错Cannot read property ‘map’ of undefined的解决方案

最近在用superset做数据分析时,用到了 Filter box筛选框,筛选其他的类型没什么问题,只要是日期有关的筛选,所有的筛选框都会消失,我安装superset是用pip安装的,版本号是0.28.1。如图报错:

首先想到的解决方案就是去github查找issues,果真很多同学都遇到了这个问题。

https://github.com/apache/incubator-superset/issues/6165

然后也找了两个解决办法:

https://github.com/apache/incubator-superset/commit/912c6f623159be69007cc9ee38b10e8adc7778ce
https://github.com/lyft/incubator-superset/commit/57410671fb90aa86433274eb6dd644b134b92dbe

但是解决的都是源码的问题,pip安装的都是编译好的,而且代码都不一样。

最终我通过看源代码,一个个打断点将这个问题解决了。

首先看文件
/usr/local/lib/python3.7/site-packages/superset/static/assets/dist/filter_box.885b5b9fd31f4d3caa48.chunk.js

这个文件代码是压缩了的,我们先将代码解压,发现我问题出现在这里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
{
                key: "renderFilters",
                value: function() {
                    return function() {
                        var e = this
                          , t = this.props
                          , n = t.filtersFields
                          , r = t.filtersChoices
                          , a = this.state.selectedValues;
                        return Object.keys(a).filter(function(e) {
                            return !(a.hasOwnProperty(e) && e in r)
                        }).forEach(function(e) {
                            var t = r[e]
                              , n = new Set(t.map(function(e) {
                                return e.id
                            }));
                            a[e].filter(function(e) {
                                return !n.has(e)
                            }).forEach(function(n) {
                                t.unshift({
                                    filter: e,
                                    id: n,
                                    text: n,
                                    metric: 0
                                })
                            })
                        }),
                        n.map(function(t) {
                            var n = t.key
                              , u = t.label
                              , s = r[n]
                              , c = Math.max.apply(Math, function(e) {
                                if (Array.isArray(e)) {
                                    for (var t = 0, n = Array(e.length); t < e.length; t++)
                                        n[t] = e[t];
                                    return n
                                }
                                return Array.from(e)
                            }(s.map(function(e) {
                                return e.metric
                            })));
                            return o.default.createElement("div", {
                                key: n,
                                className: "m-b-5"
                            }, u, o.default.createElement(p.default, {
                                placeholder: (0,
                                v.t)("Select [%s]", u),
                                key: n,
                                multi: !0,
                                value: a[n],
                                options: s.map(function(e) {
                                    var t = Math.round(e.metric / c * 100)
                                      , n = {
                                        backgroundImage: "linear-gradient(to right, lightgrey, lightgrey " + t + "%, rgba(0,0,0,0) " + t + "%",
                                        padding: "2px 5px"
                                    };
                                    return {
                                        value: e.id,
                                        label: e.id,
                                        style: n
                                    }
                                }),
                                onChange: function() {
                                    for (var t = arguments.length, r = Array(t), o = 0; o < t; o++)
                                        r[o] = arguments[o];
                                    e.changeFilter.apply(e, [n].concat(r))
                                },
                                selectComponent: l.Creatable,
                                selectWrap: i.default,
                                optionRenderer: (0,
                                h.default)(function(e) {
                                    return e.label
                                })
                            }))
                        })
                    }
                }()
            },

通过看代码逻辑var t = r[e]是一个undifined,因为上面的过滤return !(a.hasOwnProperty(e) && e in r),可以判断出e不是r里面,所有r[e]没有,而下面的t.map必须要求t是一个数组,所以这里代码报错了。

首先我去看了pip官网,发现有两个预发布版本,我直接看看这里的代码有没有修复,发现是有变化的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
key: "renderFilters",
                        value: function() {
                            return function() {
                                var e = this,
                                    t = this.props,
                                    n = t.filtersFields,
                                    r = t.filtersChoices,
                                    a = this.state.selectedValues;
                                return Object.keys(a).filter(function(e) {
                                    return a.hasOwnProperty(e) && e in r
                                }).forEach(function(e) {
                                    var t = r[e] || [],
                                        n = new Set(t.map(function(e) {
                                            return e.id
                                        }));
                                    (Array.isArray(a[e]) ? a[e] : [a[e]]).filter(function(e) {
                                        return !n.has(e)
                                    }).forEach(function(n) {
                                        t.unshift({
                                            filter: e,
                                            id: n,
                                            text: n,
                                            metric: 0
                                        })
                                    })

这里的筛选条件变了,return a.hasOwnProperty(e) && e in r,以前是非,现在与。

直接替换这里的代码,报错,不行。

那么我直接安装0.29版本呢?看看修复完成没?

1
pip install superset==0.29.0rc7

安装完成,运行superset runserver -d
报错,说是flask1.0版本废弃了命令,试用flask run 什么的。

居然运行不起来,然后我查了一下superset runserver -help

试着不用-d参数superset runserver居然成功了,真是奇怪了。

然后运行 127.0.0.1:8088,发现搜索框是好的。看来新版本是解决了这个问题。

当然如果线上运行的是0.28.1版本的,不想升级怎么办呢。

继续调试bug。

看下我打的断点输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var e = this,
                                    t = this.props,
                                    n = t.filtersFields,
                                    r = t.filtersChoices,
                                    a = this.state.selectedValues;
                                    console.log('第一步:',e)
                                    console.log('第二步:',t)
                                    console.log('第三步:',n)
                                    console.log('第四步:',r)
                                    console.log('第五步:',a)
                                return Object.keys(a).filter(function(e) {
                                    console.log('第1步:',e)
                                    console.log('第2步:',a.hasOwnProperty(e))
                                    console.log('第3步:',e in r)
                                    return !(a.hasOwnProperty(e) && e in r)
                                }).forEach(function(e) {
                                    var t = r[e];
                                    console.log('第七步:',t)
                                    console.log('第八步:',e)

那么我将t重新定义一下r[e] || [],然后发现a[e].filter这里报错,filter函数也需要是一个数组,可是a[e]是一个值,我们把它变成一个数组,Array.isArray(a[e]) ? a[e] : [a[e]]。这里改好以后,这里n.map也报错,原来这里的n已经被上面的forEach的回调函数改了,这个n应该是上面n = t.filtersFields的值,这里我们改一下将n重新定义一下,问题解决了。

说到底还是类型的问题,总共也就改了两个地方。

看看最新代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
                                    var t = r[e] || [],
                                        n = new Set(t.map(function(e) {
                                            return e.id
                                        }));
                                    (Array.isArray(a[e]) ? a[e] : [a[e]]).filter(function(e) {
                                        return !n.has(e)
                                    }).forEach(function(n) {
                                        t.unshift({
                                            filter: e,
                                            id: n,
                                            text: n,
                                            metric: 0
                                        })
                                    })

最后,再将代码压缩下,传到服务器,问题解决了。
这里我把压缩的代码放到这里,供大家直接下载。

https://pan.baidu.com/s/1P0ZGU30B0UqvyIlQowYpLg

, , ,

相关文章

4 条评论 “Superset Filter box报错Cannot read property ‘map’ of undefined的解决方案

发表评论

电子邮件地址不会被公开。 必填项已用*标注