You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用csv-writer导出嵌套JSON为CSV时嵌套字段无输出问题

问题

使用csv-writer将MongoDB中已关联(populate)的嵌套JSON数据转换为CSV时遇到问题:当csvFields仅配置{ id: 'title', title: 'Title' }这类顶层字段时,CSV生成正常;但配置嵌套字段{ id: 'task.model', title: 'task' }时,该字段无输出。已通过populate('task')关联了task文档,询问是否需要在传入writeRecords前处理文档。

使用的npm包:csv-writer

代码示例

let totalCount = await req.list.model.find(where).countDocuments();
const batchSize = 50;
const batchCount = Math.ceil(totalCount / batchSize);
const csvFields = [
    { id: 'title', title: 'Title' },
    { id: 'task.model', title: 'task' }, // 无输出
];

// 尝试解决嵌套字段显示问题
for (let i = 0; i < 1; i++) {
    let batch = await req.list.model.find(where).skip(batchSize * i).populate('task').limit(2);

    const csvWriter = createCsvWriter({
        header: csvFields,
        path: `batch_${i}.csv`,
    });

    csvWriter.writeRecords(batch)
        .then(() => console.log('csv written successfully'))
        .catch((error) => console.log(error));
};

控制台输出的batch文档JSON

[ { title: 'Dummy Task',
    starred: false,
    isTicket: true,
    isDraft: false,
    isDeleted: true,
    closed: false,
    logs: [ 60c891a95372b913afdc8ed2, 60c893c75372b913afdc93c2 ],
    created_at: 2021-06-15T11:40:25.122Z,
    updated_at: 2021-06-15T11:49:27.261Z,
    _id: 60c891a95372b913afdc8ed1,
    ticketTat: null,
    closed_at: null,
    city: 60c70bf72fa78254cbf4d410,
    region: 60c70bf72fa78254cbf4d40f,
    camera: 60c891085372b913afdc8d82,
    schedule: 60c891505372b913afdc8e2c,
    company: 60c70b882fa78254cbf4d3e7,
    task:
     { complianceType: [Object],
       monitoringType: 'Self',
       monitoringMode: 'Watch',
       status: true,
       created_at: 2022-03-30T12:56:46.619Z,
       updated_at: 2022-03-30T12:56:46.619Z,
       _id: 60c890c85372b913afdc8d71,
       checklist: 604217fb6f4c96665e780f0a,
       referenceId: 604710f054fca40eadffe735,
       model: ' Task',
       endpoint: '',
       taskType: 'Artificial Intelligence',
       actionType: 'Activity Detection',
       recordingType: 'Video',
       taggedMediaType: [],
       cooldownPeriod: '180',
       tat: null,
       tag: null,
       slug: 'wopipe',
       threshold: [],
       pushType: [Array],
       __v: 0,
       faceRecognition: false,
       version: '1',
       incidentInfo: [],
       thirdPartyIntegration: null,
       modelType: [Object],
       optimalRangeTitle: 'Ideal Value' },
    location: 60c70bf72fa78254cbf4d411,
    taskType: 'Artificial Intelligence',
    checklist: 604217fb6f4c96665e780f0a,
    assigned_at: 2021-06-15T11:40:25.122Z,
    __v: 0,
    confidence: 'high',
    uid: '7f57f0e0-05e4-4338-902a-a8b3cc1934bf',
    metadata:
     { task: 'Task',
       city: 'Buffalo',
       location: 'Lower West Side',
       region: 'New York',
       checklist: 'd1',
       schedule: 'Simulation',
       raisedBy: '' },
    timezone: 'Pacific/Honolulu',
    modelType: { type: 'process-based', label: 'Process based' },
    incidentInfo: [],
    assignTask: 60c891545372b913afdc8e36,
    raisedBy: null,
    archived: true,
    personDetected: [] },
  { title: 'Dummy2Task',
    starred: false,
    isTicket: true,
    isDraft: false,
    isDeleted: true,
    closed: false,
    logs: [ 60c893b45372b913afdc93ad, 60c893c75372b913afdc93c3 ],
    created_at: 2021-06-15T11:49:08.898Z,
    updated_at: 2021-06-15T11:49:27.261Z,
    _id: 60c893b45372b913afdc93ac,
    raisedFrom: 'Artificial Intelligence',
    eventStatus: '',
    ticketNo: '002',
    ticketStatus: 60c70b882fa78254cbf4d3f3,
    ticketTag: 60c70b882fa78254cbf4d3f2,
    ticketTat: null,
    closed_at: null,
    city: 60c70bf72fa78254cbf4d410,
    region: 60c70bf72fa78254cbf4d40f,
    camera: 60c891085372b913afdc8d82,
    schedule: 60c891505372b913afdc8e2c,
    company: 60c70b882fa78254cbf4d3e7,
    task:
     { complianceType: [Object],
       monitoringType: 'Self',
       monitoringMode: 'Watch',
       status: true,
       created_at: 2022-03-30T12:56:46.619Z,
       updated_at: 2022-03-30T12:56:46.619Z,
       _id: 60c890c85372b913afdc8d71,
       checklist: 604217fb6f4c96665e780f0a,
       referenceId: 604710f054fca40eadffe735,
       model: 'Task2',
       endpoint: '',
       taskType: 'Artificial Intelligence',
       actionType: 'Activity Detection',
       recordingType: 'Video',
       taggedMediaType: [],
       cooldownPeriod: '180',
       tat: null,
       tag: null,
       slug: 'wopipe',
       threshold: [],
       pushType: [Array],
       company: 60c70b882fa78254cbf4d3e7,
       __v: 0,
       faceRecognition: false,
       version: '1',
       incidentInfo: [],
       thirdPartyIntegration: null,
       modelType: [Object],
       optimalRangeTitle: 'Ideal Value' },
    location: 60c70bf72fa78254cbf4d411,
    taskType: 'Artificial Intelligence',
    checklist: 604217fb6f4c96665e780f0a,
    assigned_at: 2021-06-15T11:49:08.898Z,
    __v: 0,
    confidence: 'high',
    uid: '14b2b91f-308d-43be-8f5a-d9269b9139a6',
    metadata:
     { task: 'Task2',
       city: 'Buffalo',
       location: 'Lower West Side',
       region: 'New York',
       checklist: 'Pipe',
       schedule: 'Simulation2',
       raisedBy: '' },
    timezone: 'Pacific/Honolulu',
    modelType: { type: 'process-based', label: 'Process based' },
    incidentInfo: [],
    assignTask: 60c891545372b913afdc8e36,
    raisedBy: null,
    archived: true,
    personDetected: [] } ]

解决方案

是的,必须在传入writeRecords前预处理文档,因为csv-writer本身不支持通过点分隔符直接访问嵌套字段,它只能识别顶层属性。

处理方式1:手动提取嵌套字段到顶层

在获取到batch数据后,遍历每个文档,将嵌套的task.model提取为顶层属性,比如命名为task_model,然后修改csvFields的id为这个顶层属性名:

let totalCount = await req.list.model.find(where).countDocuments();
const batchSize = 50;
const batchCount = Math.ceil(totalCount / batchSize);
const csvFields = [
    { id: 'title', title: 'Title' },
    { id: 'task_model', title: 'task' }, // 修改为顶层属性名
];

for (let i = 0; i < 1; i++) {
    let batch = await req.list.model.find(where).skip(batchSize * i).populate('task').limit(2);
    
    // 预处理数据:提取嵌套字段到顶层
    const processedBatch = batch.map(item => ({
        ...item.toObject(), // 把Mongoose文档转成普通对象
        task_model: item.task?.model || '' // 提取task.model,处理可能的空值
    }));

    const csvWriter = createCsvWriter({
        header: csvFields,
        path: `batch_${i}.csv`,
    });

    csvWriter.writeRecords(processedBatch)
        .then(() => console.log('csv written successfully'))
        .catch((error) => console.log(error));
};

处理方式2:使用csv-writer的转换函数

在创建csvWriter时,通过transform选项自定义每个记录的字段映射,这样不需要修改原数据结构:

let totalCount = await req.list.model.find(where).countDocuments();
const batchSize = 50;
const batchCount = Math.ceil(totalCount / batchSize);
const csvFields = [
    { id: 'title', title: 'Title' },
    { id: 'task', title: 'task' }, // 自定义id
];

for (let i = 0; i < 1; i++) {
    let batch = await req.list.model.find(where).skip(batchSize * i).populate('task').limit(2);

    const csvWriter = createCsvWriter({
        header: csvFields,
        path: `batch_${i}.csv`,
        // 自定义转换函数,映射嵌套字段
        transform: (record) => ({
            title: record.title,
            task: record.task?.model || ''
        })
    });

    csvWriter.writeRecords(batch)
        .then(() => console.log('csv written successfully'))
        .catch((error) => console.log(error));
};

注意事项

  • 如果使用Mongoose查询结果,记得用toObject()把Mongoose文档转换为普通JavaScript对象,避免嵌套属性访问异常。
  • 添加?.可选链操作符处理task为null或undefined的情况,防止报错。

内容的提问来源于stack exchange,提问作者Mohammad Zuha Khalid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 02:57:36