【问题标题】:mongoexport with parameters + node.js + child processmongoexport 带参数 + node.js + 子进程
【发布时间】:2013-12-09 04:26:31
【问题描述】:

我正在尝试使用来自 mongodb 的 node.js 导出 csv。为此,我从以下代码开始:

app.get('/export', function(req, res) {
 var spawn = require('child_process').spawn,
 ls = spawn('mongoexport');
res.sendfile('/home/database.csv'); 
});

这很好用。然后为了使它更有用,我尝试使用参数在下面使用 mongoexport 进行编码:

 app.get('/export', function(req, res) {
 var spawn = require('child_process').spawn,
 ls = spawn('mongoexport --db lms --collection databases --fields firstname,lastname,email,daytimePhone,addressOne,city,state,postalCode,areaOfStudy,currentEducationLevel,company --csv --out /home/database.csv');
res.sendfile('/home/database.csv') 

});

这会引发异常:

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: spawn ENOENT
    at errnoException (child_process.js:980:11)
    at Process.ChildProcess._handle.onexit (child_process.js:771:34)

然后我尝试只使用一个参数,但它给出了相同的错误:(

我也试过这个,看看参数是否以这种方式工作,但同样的错误:

spawn('mongoexport',['--csv']);

【问题讨论】:

    标签: javascript node.js mongodb csv


    【解决方案1】:

    spawn 的语法是:

    spawn(<command>, [array of arguments]);
    

    例如,使用-l /home 选项执行ls 命令将如下所示:

    ls = spawn('ls', ['-l', '/home'];
    

    所以您的spawn('mongoexport',['--csv']); 正朝着正确的方向前进,但mongoexport --csv 无效。这就是为什么你会出错。 mongoexport 需要的不仅仅是--csv。就像上面所做的一样,例如,您需要指定数据库名称(-d "lms")、集合名称(-c "databases")、字段名称(--fields firstname,lastname)等。

    在你的情况下,它应该是这样的:

     var spawn = require('child_process').spawn;
     app.get('/export', function(req, res) {
         var mongoExport = spawn('mongoexport', [ 
             '--db', 'lms', '--collection', 'databases', 
             '--fields',
             'firstname,lastname,email,daytimePhone,addressOne,city,state,postalCode,areaOfStudy,currentEducationLevel,company',   
             '--csv'
         ]);
    
         res.set('Content-Type', 'text/plain');
         mongoExport.stdout.on('data', function (data) {
             if (data) {
                 // You can change or add something else here to the
                 // reponse if you like before returning it.  Count
                 // number of entries returned by mongoexport for example
                 res.send(data.toString());
             } else {
                 res.send('mongoexport returns no data');
             }
         });
    }
    

    【讨论】:

    • 好的 csv 可以正确生成...但我猜这行会在生成完成之前执行:res.sendfile('/home/database.csv')。有任何回调吗?
    • 这只是让我下载了一个名为“export”的文件,没有应用任何参数:(
    • beNerd,我目前没有环境来测试您上面的代码并查看它在调试器中的作用。当我有一些周期时,我会这样做。同时,在调用 res.senfile() 之前尝试设置 Content-Type。像这样: res.set('Content-Type', 'text/plain');
    • @beNerd,正如 robertklep 所说,创建 /home/database.csv 会引入竞争条件。所以避免它是好的。一种方法是像 robertklep 建议的那样将输出通过管道传输到 res 。另一种方法是将事件处理程序添加到“数据”事件。这种方法允许您在响应的输出之后添加一些内容。你可以做一些事情,比如改变结果、计数条目等。因为 robertklep 已经放下了管道解决方案。我将修改我的答案以处理“数据”事件。
    • 这进入非终止条件和 nginx 超时!
    【解决方案2】:

    您的代码存在竞争条件,/home/database.csv 可能会被多个(几乎)同时进入的/export 请求截断/覆盖。

    使用 Ben 提供的代码,我会将 mongoexport 的输出直接通过管道传输到响应对象,因此不需要使用临时文件:

    app.get('/export', function(req, res) {
      // Set correct content-type
      res.set('Content-Type', 'text/csv');
      // Export collection and pipe to `res`
      spawn('mongoexport', [ 
        '--db', 'lms', '--collection', 'databases', 
        '--fields', 'firstname,lastname,email,daytimePhone,addressOne,city,state,postalCode,areaOfStudy,currentEducationLevel,company', 
        '--csv'
      ]).stdout.pipe(res);
    });
    

    我个人会使用 MongoDB 驱动程序和 csv 直接从 Node 生成 CSV。

    【讨论】:

    • 我可以知道为什么我不应该采用这种方法并按照您的建议直接生成 csv 吗?
    • @beNerd 我不是建议你不应该,只是我自己可能不会这样做:)(为请求生成新进程需要相当多的资源,但如果它不经常被调用,那可能没关系)
    • 我尝试了 ben 的方法,但它只是让我下载了一个名为“export”的文件,没有应用任何参数:(
    • @beNerd 首先从一个简单的脚本开始,请参阅this gist。看看有什么作用。
    • 它只是在终端中显示“已连接到 127.0.0.1”,没有其他内容
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 2012-10-14
    • 2019-03-29
    相关资源
    最近更新 更多