我在我的Heroku Node.js服务器上运行了这段代码,以便获得几百行的CSV,但是R14 - Memory Quota Exceeded失败了。当DB中行较少时,它工作得很好,即使没有写入文件,我也能够将CSV直接写入HTTP响应。我能做些什么来解决这个问题?
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");
}
});
}
});
});
};
```发布于 2019-02-05 03:15:41
在我们深入研究代码之前,我想问一问:这个CSV真的需要实时/按需地生成吗?如果答案是否定的,您可能可以使用蒙古出口运行cron作业。这样,你就可以完全避开Node了。
库不受内存限制的影响。他们也创造物体!在本例中,当您将许多Follow条目加载到follows中时,它就开始了。当您将所有这些数据转换为CSV时,这种情况就更加复杂了。在幕后,您将大量数据加载到一个庞大的对象数组中,然后将这个庞大的对象数组转换为一个巨大的字符串。
幸运的是,json2csv有一个流API。这意味着,与其在内存中一次处理所有的结果,不如按块构建CSV。由于我们处理的是对象数组,而不是字符串、缓冲区和原始数据数组,所以您应该查看“对象模式”。
因此,您要做的是设置一个管道--一组函数连接在一起,一个接一个地调用,前面的输出是下一个函数的输入。数据被流到这个管道中,对它传递的每一个转换函数进行转换,直到它到达终点为止。
在你的例子中,它应该是这样的:
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。这样,整个程序就会使用流,而且在任何时候都不会将所有数据存储在内存中。它们一次被装载、加工和冲洗几块。
const stream = streamFromMongoose.pipe(json2csv).pipe(output)https://codereview.stackexchange.com/questions/212859
复制相似问题