Node.jsを用いたMongoDBデータのExcel・PDF変換実装

Excelファイル生成処理の構築

MongoDBから取得したJSONデータをExcel形式に変換する際の実装フローを説明します。データストリーム処理を基盤とし、メモリ効率を最適化した実装が重要です。

async function generateExcel(collectionName) {
  const { client, db } = await createMongoConnection();
  try {
    const targetCollection = db.collection(collectionName);
    const cursor = targetCollection.find(
      {}, 
      { projection: { _id: 0, productName: 1, category: 1, unitPrice: 1 } }
    );

    const headerLabels = ['商品名', 'カテゴリ', '単価'];
    const rowData = [];
    
    await cursor.forEach(item => {
      rowData.push([
        item.productName || '',
        item.category || '',
        item.unitPrice ? `¥${item.unitPrice}` : ''
      ]);
    });

    const worksheetConfig = {
      sheetName: '商品一覧',
      headers: headerLabels,
      body: rowData
    };

    return ExcelBuilder.create(worksheetConfig);
  } finally {
    await client.close();
  }
}

ポイントとして、カーソル処理を採用し大量データに対応可能にしています。ヘッダー定義とデータ整形を分離し、後述のPDF出力と処理フローを統一しています。出力時はContent-Dispositionヘッダーでファイル名を日時付きで指定し、日本語文字化けを回避しています。

PDFドキュメントの動的生成

Excelと同様のデータソースからPDFを生成する実装では、pdfkit-tableの拡張機能を活用します。表形式データのレンダリングに特化した処理が必須です。

async function createPdfDocument(collectionName) {
  const { db } = await createMongoConnection();
  const inventoryCollection = db.collection(collectionName);
  
  const inventoryData = await inventoryCollection.aggregate([
    {
      $project: {
        itemName: 1,
        stockType: 1,
        currentStock: { $subtract: ['$inbound', '$outbound'] }
      }
    }
  ]).toArray();

  const pdfDoc = new PDFDocument({ size: 'A4', margin: 30 });
  const tableConfig = {
    headers: [
      { label: '品目', property: 'itemName', width: 150 },
      { label: '種別', property: 'stockType', width: 100 },
      { label: '在庫数', property: 'currentStock', width: 80 }
    ],
    datas: inventoryData.map(item => ({
      itemName: item.itemName,
      stockType: item.stockType,
      currentStock: item.currentStock
    }))
  };

  await pdfDoc.addTable(tableConfig, {
    startY: 50,
    columnSpacing: 5
  });

  return new Promise(resolve => {
    const chunks = [];
    pdfDoc.on('data', chunks.push.bind(chunks));
    pdfDoc.on('end', () => resolve(Buffer.concat(chunks)));
    pdfDoc.end();
  });
}

注意点として、pdfkit-tableのバージョン互換性に配慮し、集計結果のマッピング処理を明示的に実装しています。ストリーム処理によるバッファ生成でメモリ消費を抑制し、特に大量データ時のパフォーマンスを向上させています。テーブルレイアウトはA4用紙の余白を考慮した寸法設定としています。

タグ: Node.js MongoDB node-xlsx pdfkit-table Stream処理

7月12日 23:22 投稿