40

嘿,我正在尝试从 node.js 导出 csv(从 mongodb 中提取数据)。我已经将数据拉出并用逗号分隔,但现在我正试图弄清楚如何实际发送它......我将此代码粘贴在我的路由文件中。关于如何获取数据数组并将其直接发送给用户以供请求下载的任何建议。

这是代码:(我尝试了代码的底部第二个功能)

exports.downloadContacts = function(req, res) {
    async.waterfall([
        function(callback) {
            var source = [];
            Friend.find({userId: req.signedCookies.userid}, function(err, friends) {
                if(err) {console.log('err with friends for download');
                } else {
                    var userMap = {};
                    var friendIds = friends.map(function (user) {
                        userMap[user.friend_id] = user;
                        return user.friend_id;
                    });
                    console.log(friends);
                    User.find({_id: {$in: friendIds}}, function(err, users) {
                        if(err) {console.log(err); 
                        } else {
                            for(var i = 0; i < users.length; i++) {
                                console.log('users')
                                //console.log(users[i]);
                                source.push(users[i].firstNameTrue, users[i].lastNameTrue, users[i].emailTrue, users[i].phone, users[i].emailList, users[i].phoneList)
                            }
                            console.log(source);
                            callback(null, source);
                        }


                    });
                }


            });

        }
    ],
    function(err, source) {
        var result = [];

        res.contentType('csv');

        csv()
        .from(source)
        .on('data', function(data){ 
            result.push(data.join());
        })
        .on('end', function(){
            res.send(result.join('\n'));
        });
    });     
};
4

12 回答 12

39

这是我所做的:

  1. 使用json2csv从 mongodb 数据构建 csv 数据

var json2csv = require('json2csv');
var fields = ['name', 'phone', 'mobile', 'email', 'address', 'notes'];
var fieldNames = ['Name', 'Phone', 'Mobile', 'Email', 'Address', 'Notes'];
var data = json2csv({ data: docs, fields: fields, fieldNames: fieldNames });
  1. 向客户端发送 csv 数据

res.attachment('filename.csv');
res.status(200).send(data);
于 2016-09-23T04:13:32.957 回答
33

您是否尝试过类似的内容类型为“application/octet-stream”

res.set('Content-Type', 'application/octet-stream');
res.send(<your data>);

或者干脆

res.send(Buffer.from(<your data>));

快递发送()文档。

于 2013-08-19T04:14:52.403 回答
15

json2csv包自编写最高投票答案以来已更新,较新版本的语法略有不同:

        var { Parser } = require('json2csv')

        const fields = [{
            label: 'header 1',
            value: 'field1_name'
        }, {
            label: 'header 2',
            value: 'field2_name'
        }]

        const json2csv = new Parser({ fields: fields })

        try {
            const csv = json2csv.parse(data)
            res.attachment('data.csv')
            res.status(200).send(csv)
        } catch (error) {
            console.log('error:', error.message)
            res.status(500).send(error.message)
        }

res.attachment 是一个函数而不是一个属性。需要删除等号才能正常工作。

于 2019-05-23T01:25:08.940 回答
5

根据@VierTD 的回答,您必须使用 json2csv 从 mongodb 数据构建 csv 数据。

使用依赖项更新 Package.json:

  "dependencies": {
    "mongodb": "^2.2.10",
    "json2csv": "*",
    "express": "*"
  }

创建 json2CSV 对象,记住这是映射您的文档(数据库表),因此“字段”上的名称必须与数据库表匹配,字段名称由您决定,但也很重要,因为这些是 CSV 文件列名称:

var json2csv = require('json2csv');
var fields = ['name', 'phone', 'mobile', 'email', 'address', 'notes'];
var fieldNames = ['Name', 'Phone', 'Mobile', 'Email', 'Address', 'Notes'];
var data = json2csv({ data: docs, fields: fields, fieldNames: fieldNames });

向客户端发送 csv 数据:

res.attachment('filename.csv');
res.status(200).send(data);

此代码显示如何基于 mongo db 文档(数据库表)导出 csv 文件

我创建了一个github存储库,对这个想法进行了简短的采样,还在Mongo Lab 网站上创建了一个包含虚拟数据的数据库,因此该代码将立即在您的计算机上运行。基于 @VietTD 的答案。

如果您有兴趣测试此代码,请记住更改以下行。

更改数据库 url(使用您自己的数据库这可行,但仅用于显示目的)。

        var url = 'mongodb://admin:detroit123@ds063946.mlab.com:63946/misale_dev';

更改目标文档(或数据库表)。

var collection = db.collection('_dummy');

更改文档列(或 db 表的列字段):

var fields = ['_id', 'JobID', 'LastApplied'];

最后为您设置 CSV 标题列名以及 CSV 文件名:

var fieldNames = ['ID_OR_PK', 'JOB_UNIQUE_ID_TITLE', 'APPLICATION_DATE'];

最后但并非最不重要的:

res.attachment('yourfilenamehere.csv');

请随时改进示例代码,我将不胜感激!或者只是下载它并查看代码。它已经带有一个数据库,所以它很容易理解和运行,在这种情况下你不关心这里是整个代码,也许你会看到一些有趣的东西:

//
// EXPRESS JS SERVER INITI
//
var express = require('express')
var app = express()

//
// MONGO DB INIT
//
var MongoClient = require('mongodb').MongoClient, assert = require('assert');
app.get('/', function (req, res) {
    var url = 'mongodb://admin:detroit123@ds063946.mlab.com:63946/misale_dev';
    //
    // This function should be used for migrating a db table to a TBD format
    //
    var migrateMongoDBTable = function(db, callback) {
        // Get the documents collection
        console.log("Reading database records");
        // Get the documents collection
        var collection = db.collection('_dummy');
        // Find some documents
        //collection.find({'a': 3}).toArray(function(err, docs) {
        collection.find({}).toArray(function(err, docs) {
          assert.equal(err, null);
          //console.log(docs);
          //console.log('docs.length ---> ', docs.length);
          console.log('Creating CSV...');
          //console.log('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=');
          var json2csv = require('json2csv');
          var fields = ['_id', 'JobID', 'LastApplied'];
          var fieldNames = ['ID_OR_PK', 'JOB_UNIQUE_ID_TITLE', 'APPLICATION_DATE'];
          var data = json2csv({ data: docs, fields: fields, fieldNames: fieldNames });
          //console.log('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=');
          // EXPORT FILE
          res.attachment('yourfilenamehere.csv');
          res.status(200).send(data);
          callback(docs);
        });
    };

    // Use connect method to connect to the server
    MongoClient.connect(url, function(err, db) {
      assert.equal(null, err);
      console.log("Connected successfully to server");
      //
      // migrate db table to some format TBD
      //
      migrateMongoDBTable(db, function() {
        db.close();
      });
    });

})

app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
})
// Connection URL
//var url = 'mongodb://localhost:27017/myproject';
于 2016-12-09T14:29:48.263 回答
2

我不完全确定你的问题是什么,但我认为你正在寻找什么可以通过设置 Content Disposition 标题来解决。在另一个 SO 问题上查看此响应:https ://stackoverflow.com/a/7288883/2320243 。

于 2013-08-19T03:35:10.240 回答
2

使用 json2csv 库,您可以从 mongodb 数据中导出 csv。

const json2csv = require('json2csv').parse;

//For unique file name
const dateTime = new Date().toISOString().slice(-24).replace(/\D/g, 
'').slice(0, 14); 

const filePath = path.join(__dirname, "../../../", "public", "exports", "csv-" 
+ dateTime + ".csv");

let csv; 

const student = await req.db.collection('Student').find({}).toArray();

// Logging student
// [{id:1,name:"John",country:"USA"},{id:1,name:"Ronny",country:"Germany"}]

const fields = ['id','name','country'];

 try {
    csv = json2csv(student, {fields});
 } catch (err) {
    return res.status(500).json({err});
 }

 fs.writeFile(filePath, csv, function (err) {
    if (err) {
        return res.json(err).status(500);
    }
    else {
        setTimeout(function () {
            fs.unlink(filePath, function (err) { // delete file after 30 sec
            if (err) {
                console.error(err);
            }
            console.log('File has been Deleted');
        });

    }, 30000);
        res.download(filePath);
    }
})
于 2018-11-01T06:50:04.347 回答
1

Express-csv 是一个很棒的模块,用于将 csv 内容写入来自 node.js 服务器的流,它将作为响应发送给客户端(并作为文件下载)。非常容易使用。

app.get('/', function(req, res) {
  res.csv([
    ["a", "b", "c"]
  , ["d", "e", "f"]
  ]);
});

文档:https ://www.npmjs.com/package/express-csv

当您传递一个对象时,您需要明确地预先添加标题(如果您想要它们)。这是我使用npm mysql的示例

router.route('/api/report')
    .get(function(req, res) {
            query = connection.query('select * from table where table_id=1;', function(err, rows, fields) {
                if (err) {
                    res.send(err);
                }
                var headers = {};
                for (key in rows[0]) {
                    headers[key] = key;
                }
                rows.unshift(headers);
                res.csv(rows);
            });
    });
于 2015-02-09T01:05:59.397 回答
0

我在这个http://nikgrozev.com/2017/05/10/mongo-query-to-CSV-download-expressjs/找到了一个解决方案

关键词

将输出流式传输到 HTTP 响应

于 2018-07-23T14:33:15.017 回答
0

如果您不想使用模块,我会将其分为两个步骤:

第 1 步:将 JSON 转换为平面数组

这里重要的是 JSON 键成为数组的第一行

/**
 * Convert JSON list of objects to 2D array
 * Headers from first list item create first row of array
 * @param Array JSON list of objects
 * @return Array 2D array with first row as the object keys from the first object in list
 */
function json2array (data) {
  let headers = []
  let output = new Array(data.length + 1)
  // get object keys for first item if one exists
  if (data.length > 0) headers = Object.keys(data[0])
  output[0] = headers
  data.forEach((dataRow, row) => {
    const outputRow = new Array(headers.length)
    // populate array
    headers.forEach((header, column) => {
      outputRow[column] = dataRow[header]
    })
    output[row + 1] = outputRow
  })
  return output
}

// jsonData = [{email: "user1@example.com", name: "John"}, {email: "user2@example.com", name: "Jane"}] 

const arr = json2array(jsonData)

// arr = [["email", "name"],["user1@example.comm", "John"],["user2@example.com", "Jane"]]

第 2 步:将二维数组转换为 CSV

然后您可以保存到文件或输出到浏览器等。

/**
 * Convert a 2D array into CSV notation
 * @param Array a 2D array with the first row as headers
 * @return String CSV-formatted text
 */
function array2csv (arr) {
  let csvOut = ''
  arr.forEach((arrRow, rowNum) => {
    let csvRow = ''
    arrRow.forEach((value, colNum) => {
      if (colNum > 0) csvRow += ',' // comma-separate columns
      const valueType = typeof(value)
      if (valueType == 'number') csvRow += value
      else if (valueType == 'boolean') csvRow += value ? 'TRUE':'FALSE'
      // quote strings and handle existing quotes
      else csvRow += '"' + value.replace(/"/g, '""') + '"'
    })
    if (rowNum > 0) csvOut += "\n" // newline-split rows
    csvOut += csvRow
  })
  return csvOut
}

const csvOut = array2csv(arr)

/*
"email","name"
"user1@example.com","John"
"user2@example.com","Jane"
*/

这些方法很O(n)复杂。

于 2021-11-12T12:23:08.093 回答
0

这是如何生成csv文件的过程

安装

npm i fs-extra

像这样创建一个文件

const fse = require('fs-extra');
const fs = require('fs');
const csvInstant_save = exports.csvInstant_save = (data=[], filePath='') => {

    let csvContent = "";

    let header = Object.keys(data[0]);
    csvContent += header + "\r\n";
    
    data.forEach(function(rowArray) {
        let row_data = Object.values(rowArray)
        let row = row_data.join(",");
        csvContent += row + "\r\n";
    });
    
    fse.ensureFileSync(filePath)

    const writeStream = fs.createWriteStream(filePath, {encoding: 'utf8'});
    writeStream.write(csvContent);
}

像这样调用函数

const exceljshelper = require('../helpers/exceljshelper');

exceljshelper.excelInstant_save(data, './app/public/uploads/exports/user/excel/users-data-'+todayYMD+'.csv')

于 2021-12-27T05:35:23.440 回答
0

真实的例子可能有帮助

后端 - NodeJs

路由器.js

var { Parser } = require('json2csv');
const dataService = require('../service');

router.get('/exportData', cors(), async (req, res) => {
    const list = await dataService.getData(req);
    const fields = [
        { label: 'Id', value: 'Id' },
        { label: 'Name', value: 'Name' },
        { label: 'Age', value: 'Age' },
        { label: 'Date', value: 'Date' },
    ];
    const json2csv = new Parser({ fields: fields });
    const csv = json2csv.parse(list);
    res.status(200).send(Buffer.from(csv));
});

服务.js

const sequelize = require('sequelize');
const moment = require('moment');
const { CallLogs } = require("../models");
const { Op } = sequelize;

exports.getData = async (req) => {
    let list = [];
    try {
        const { query: { Date_gte, Date_lt } } = req;
        const request = {
            where: {},
            order: [['Date', 'DESC']],
        };
        if (Date_gte && Date_lt) {
            request.where.Date = {
                [Op.between]: [Date_gte, Date_lt]
            }
        } else {
            if (Date_gte) {
                request.where.Date = {
                    [Op.gte]: Date_gte
                }
            }
            if (Date_lt) {
                request.where.Date = {
                    [Op.lt]: Date_lt
                }
            }
        }

        list = JSON.parse(JSON.stringify(await CallLogs.findAll(request)));

        list = list.map(c => {
            let obj = { ...c };
            obj.Date = moment(new Date(obj.Date)).format('DD.MM.YYYY');
            return obj;
        });
    } catch (error) {
        console.log(error);
    }
    return list;
}

前端 - 反应

应用程序.js

import download from "downloadjs";
import Axios from "axios";

async function exportResultToExcel() {
    try {
        let filters = { ...this.state.filter };
        const res = (await Axios.get(`api/exportData`, {
            params: filters,
            responseType: "blob"
        })).data;
        if (res) {
            download(res, new Date().toLocaleDateString() + '-data.csv');
        } else {
            alert("Data not found");
        }
    } catch (error) {
        console.log(error);
    }
}

<Button onClick={() => { this.exportResultToExcel() }}>Export to CSV</Button>
于 2021-12-28T13:57:09.950 回答
-1

回答为时已晚,但对于 2021 年需要优化且耗时更少的解决方案的人来说

以上所有解决方案都很好,但有

  1. 时间复杂度 O(n)

  2. 存储复杂性或高内存使用问题有时应用程序可能会因为请求过多而崩溃

解决方案:当用户对 DB 执行 CRUD 操作时,例如在 put 请求中,维护一个同步的 CSV 文件

app.put('/product/:id', (res,req)=>{
    // step 1 do update operation in db
    // step 2 do update operation in CSV file

    return res.send('OK 200')

})

所以下次当用户请求 CSV 时,用户可以立即获取 CSV 文件

快乐编码:)

于 2021-01-13T08:59:56.193 回答