处理JSON对象太大而无法放入内存

时间:2013-12-19 19:35:25

标签: javascript json node.js firebase jsonstream

我有一个Firebase数据库的转储,表示存储在JSON中的Users表。我想对它运行一些数据分析,但问题是它太大而无法完全加载到内存中并使用纯JavaScript(或_和类似的库)进行操作。

到目前为止,我一直在使用JSONStream包以一口大小的块处理我的数据(它为JSON转储中的每个用户调用一次回调)。

我现在遇到了障碍,因为我想根据其值过滤我的用户ID。我试图回答的“问题”的形式是“哪些用户x”,而之前我只是问“有多少用户x”而不需要知道他们是谁。

数据格式如下:

{
    users: {
        123: {
            foo: 4
        },
        567: {
            foo: 8
        }
    }
}

我想要做的主要是根据123的值获取上面的用户ID(567foo)。现在,如果这是一个小列表,使用_.each之类的东西迭代键和值并提取我想要的键将是微不足道的。

不幸的是,因为它不适合不起作用的内存。使用JSONStream,我可以使用var parser = JSONStream.parse('users.*');对其进行迭代,然后将其组合成一个处理它的函数:

var stream = fs.createReadStream('my.json');

stream.pipe(parser);

parser.on('data', function(user) {
    // user is equal to { foo: bar } here
    // so it is trivial to do my filter
    // but I don't know which user ID owns the data
});

但问题是我无法访问代表我传递给JSONStream.parse的星形通配符的密钥。换句话说,我不知道{ foo: bar}代表用户123还是用户567

问题有两个:

  1. 如何从回调中获取当前路径?
  2. 有没有更好的方法来处理这个太大而无法容纳在内存中的JSON数据?

1 个答案:

答案 0 :(得分:4)

我继续编辑JSONStream以添加此功能。

如果有人遇到此问题并希望以类似方式对其进行修补,则可以替换之前的line 83

stream.queue(this.value[this.key])

用这个:

var ret = {};
ret[this.key] = this.value[this.key];

stream.queue(ret);

在原始问题的代码示例中,而不是user在回调中等于{ foo: bar },现在它将是{ uid: { foo: bar } }

由于这是一个重大变化,我没有向原始项目提交拉取请求,但我确实将其留在了问题中,以防他们希望将来为此添加标记或选项。