使用Admin SDK批量写入Firestore

时间:2018-06-24 16:49:50

标签: javascript node.js firebase google-cloud-firestore

我有一个非常大的ASCII平面文件(150万行)需要读取。它基本上是制造商提供的零件清单。我想使用Firestore托管它。

作为.csv文件,其最大容量为250GB。我能够使用Windows PowerShell将其转换为JSON文件,现在它的重量超过1GB。

如何将这些数据导入Firestore?我认为Admin SDK和批处理写入将是一种方法。因此,我完成了所有设置并组装了一个节点脚本,但是Firestore的Admin SDK文档很薄。

我的节点脚本在下面,但是抛出错误FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory

var admin = require("firebase-admin");
var serviceAccount = require("./--------------------------.json");
var fs = require('fs');
var myCsvFile = "./global.csv"
var parse = require('csv-parse');
require('should');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://g--------b.firebaseio.com"
});

var firestore = admin.firestore();
var writeBatch = firestore.batch();
var myRef = firestore.collection("foo").doc();
var obj = {};


fs.createReadStream(myCsvFile)
    .pipe(parse({delimiter: '|',relax_column_count:true,quote: ''}))
    .on('data', function(csvrow) {
        if(csvrow[1]){
            obj.family = csvrow[1];
        }
        if(csvrow[2]){
            obj.series = csvrow[2];
        }
        if(csvrow[3]){
            obj.sku = csvrow[3];
        }
        if(csvrow[5]){
            obj.description = csvrow[5];
        }
        if(csvrow[7]){
            obj.price = csvrow[7];  
        }
        writeBatch.set(myRef, obj);
    })
    .on('end',function() {
      writeBatch.commit()
    });

3 个答案:

答案 0 :(得分:1)

在规定的范围内进行批量写入不会对您造成任何问题。我认为您目前没有其他选择。

答案 1 :(得分:1)

每秒可写入

500个条目。因此,关键是将.commit的速率限制为每秒1,并将batch.set的速率限制为每次提交500以下。我使用aynch / await作为速率限制器,以及将promise.all推入.set es递增数组的.batch样式模式。

哦,还有最后一件事-我不得不告诉节点--max-old-space-size开关使用更多的内存。

以下脚本是从High Tech Telecom复制的:

var admin = require("firebase-admin");
var serviceAccount = require("./your-firebase-project-service-account-key.json");
var fs = require('fs');
var csvFile = "./my-huge-file.csv"
var parse = require('csv-parse');
require('should');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://your-project.firebaseio.com"
});

var firestore = admin.firestore();
var thisRef;
var obj = {};
var counter = 0;
var commitCounter = 0;
var batches = [];
batches[commitCounter] = firestore.batch();

fs.createReadStream(csvFile)
    .pipe(
      parse({delimiter: '|',relax_column_count:true,quote: ''})
  )
    .on('data', function(csvrow) {
      if(counter <= 498){
          if(csvrow[1]){
              obj.family = csvrow[1];
          }
          if(csvrow[2]){
              obj.series = csvrow[2];
          }
          if(csvrow[3]){
              obj.sku = csvrow[3];
          }
          if(csvrow[4]){
              obj.description = csvrow[4];
          }
          if(csvrow[6]){
              obj.price = csvrow[6];  
          }
          thisRef = firestore.collection("your-collection-name").doc();
          batches[commitCounter].set(thisRef, obj);
          counter = counter + 1;          
      } else {
          counter = 0;
          commitCounter = commitCounter + 1;
          batches[commitCounter] = firestore.batch();
      }
    })
    .on('end',function() {
      writeToDb(batches);
    });

function oneSecond() {
  return new Promise(resolve => {
      setTimeout(() => {
          resolve('resolved');
      }, 1010);
  });
}

async function writeToDb(arr) {
  console.log("beginning write");
  for (var i = 0; i < arr.length; i++) {
      await oneSecond();
      arr[i].commit().then(function () {
          console.log("wrote batch " + i);
      });
  }
  console.log("done.");
}

答案 2 :(得分:0)

简短说明:您永远不会重置obj(obj = {}),因此基本上您一直都在插入相同的记录。