首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >由于缺少内存,json2CSV失败了

由于缺少内存,json2CSV失败了
EN

Code Review用户
提问于 2019-02-04 16:39:49
回答 1查看 1.2K关注 0票数 3

我在我的Heroku Node.js服务器上运行了这段代码,以便获得几百行的CSV,但是R14 - Memory Quota Exceeded失败了。当DB中行较少时,它工作得很好,即使没有写入文件,我也能够将CSV直接写入HTTP响应。我能做些什么来解决这个问题?

代码语言:javascript
复制
var mongoose = require("mongoose");
const fs = require('fs');
const path = require('path')
const Json2csvParser = require("json2csv").Parser;
var Follow = require("../models/follow");
const fields = ["brand", "handle", "title", "followDateTime", "posts", "followers", "following", "description", "link", "isPrivate"];

module.exports = function(app) {
    app.get("/csv", (req, res) => {
        Follow.find({}).exec(function(err, follows) {
            if (err) {
                res.status(500).send(err);
            } else {
                let csv;
                try {
                    const json2csvParser = new Json2csvParser({ fields });                  
                    csv = json2csvParser.parse(follows);
                } catch (err) {
                    return res.status(500).json({ err });
                }
                const dateTime = Date.now();
                const filePath = path.join(__dirname, "..", "public", "exports", "csv-" + dateTime + ".csv");

                fs.writeFile(filePath, csv, function (err) {
                    if (err) {
                      return res.json(err).status(500);
                    }
                    else {
                      setTimeout(function () {
                        fs.unlinkSync(filePath); // delete this file after 30 seconds
                      }, 30000)
                      return res.json("/exports/csv-" + dateTime + ".csv");
                    }
                  });
            }
        });
    });
};
```
代码语言:javascript
复制
EN

回答 1

Code Review用户

发布于 2019-02-05 03:15:41

在我们深入研究代码之前,我想问一问:这个CSV真的需要实时/按需地生成吗?如果答案是否定的,您可能可以使用蒙古出口运行cron作业。这样,你就可以完全避开Node了。

库不受内存限制的影响。他们也创造物体!在本例中,当您将许多Follow条目加载到follows中时,它就开始了。当您将所有这些数据转换为CSV时,这种情况就更加复杂了。在幕后,您将大量数据加载到一个庞大的对象数组中,然后将这个庞大的对象数组转换为一个巨大的字符串。

幸运的是,json2csv有一个流API。这意味着,与其在内存中一次处理所有的结果,不如按块构建CSV。由于我们处理的是对象数组,而不是字符串、缓冲区和原始数据数组,所以您应该查看“对象模式”。

因此,您要做的是设置一个管道--一组函数连接在一起,一个接一个地调用,前面的输出是下一个函数的输入。数据被流到这个管道中,对它传递的每一个转换函数进行转换,直到它到达终点为止。

在你的例子中,它应该是这样的:

代码语言:javascript
复制
const { createWriteStream } = require('fs')
const { Readable } = require('stream')
const { Transform } = require('json2csv')

// ...somewhere in your controller code...

// With streams, everything starts with and ends with a stream. This is the start.
const input = new Readable({ objectMode: true })
input._read = () => {} // Not sure what this is for, really.

// We set up the transformer, the thing that converts your object into CSV rows.
const json2csv = new Transform ({ fields }, { objectMode: true })

// Create a stream to the file. This is the end of the line.
const output = createWriteStream('./output')

// You can optionally listen to the output when all the data is flushed
output.on('finish', () => { /* all done */ })

// We connect the dots. So this reads like:
// 1. Read data into input.
// 2. Input gets fed into json2csv.
// 3. The output of json2csv is fed into output (which is our file).
const stream = input.pipe(json2csv).pipe(output)

// Start pumping data into the stream. You could use setInterval if you wanted.
follows.forEach(o => input.push(obj))

// Close the input.
input.push(null) 

现在我对猫鼬不太熟悉了。但是,如果它有一个将结果公开为流的API,则可以跳过对象模式并将该流输送到json2csv。这样,整个程序就会使用流,而且在任何时候都不会将所有数据存储在内存中。它们一次被装载、加工和冲洗几块。

代码语言:javascript
复制
const stream = streamFromMongoose.pipe(json2csv).pipe(output)
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/212859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档