当数据超过500行时,Firestore动态批量写入

时间:2018-07-24 18:55:06

标签: firebase google-cloud-firestore google-cloud-functions

因此,当我将CSV文件上传到存储设备时,我已经创建了一个Cloud Function来触发。该函数应读取CSV文件,将其行转换为JSON对象数组,然后将数据插入我的Firestore集合中。

阅读和转换效果很好。我的问题在于尝试在Firestore上保存数据时。

由于CSV文件可能有很多行,因此我使用了批量写入,并且我们知道:

  

批处理写入对于将大型数据集迁移到Cloud Firestore也很有用。批处理写入最多可包含500个操作,而批处理操作合在一起可减少连接开销,从而加快数据迁移速度。

因此,当CSV数据集大于500时,我不得不创建一种动态方式来使用批量写入。

这是我创建和提交批处理的代码段:

const batches: Array<any> = new Array;
while(linesArray.length > 0) {
  if(linesArray.length - 1 > 499) {
    batches.push(linesArray.splice(0, 499))
  } else {
    batches.push(linesArray.splice(0));
  }
}
batches.forEach((_arr, i) => {
  _arr.forEach(line => {
    if (line) {
      data.push(JsonUtil.toSkill(line));
    }
  });
  this.db.batchSet(data, 'skills')
    .then(
      (result) => console.log('batch ' + i + ' committed', result),
      (error) => console.log('batch ' + i + ' error', error)
    );
  data = [];
});

请记住,linesArray是一组已经转换为JSON对象的CSV行,而JsonUtil.toSkill是一个实用函数,仅返回要保存在Firestore中的数据。 linesArrayJsonUtil.toSkill均按预期工作。

函数this.db.batchSet定义如下:

batchSet(data: Array<Object>, path: string) {
  const collection = this.db.collection(path);
  const batch: any = this.db.batch();
  data.forEach(val => {
    batch.set(collection.doc(), val);
  });
  return batch.commit();
}

执行上述代码后,Cloud Function的状态为“ ok”,但是几分钟后,出现以下错误:

{ Error: 10 ABORTED: The referenced transaction has expired or is no longer valid.
    at Object.exports.createStatusError (/user_code/node_modules/firebase-admin/node_modules/grpc/src/common.js:87:15)
    at Object.onReceiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:1188:28)
    at InterceptingListener._callNext (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:564:42)
    at InterceptingListener.onReceiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:614:8)
    at callback (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:841:24)
  code: 10,
  metadata: Metadata { _internal_repr: {} },
  details: 'The referenced transaction has expired or is no longer valid.' }

另一方面,如果我将上面显示的代码块替换为以下内容:

const array0 = linesArray.slice(0, 500);
const array1 = linesArray.slice(500, 1000);
const array2 = linesArray.slice(1000, 1500);
const array3 = linesArray.slice(1500);
array0.forEach(line => {
  if (line) {
    data.push(JsonUtil.toSkill(line));
  }
});
this.db.batchSet(data, 'skills');
data = [];
array1.forEach(line => {
  if (line) {
    data.push(JsonUtil.toSkill(line));
  }
});
this.db.batchSet(data, 'skills');
data = [];
array2.forEach(line => {
  if (line) {
    data.push(JsonUtil.toSkill(line));
  }
});
this.db.batchSet(data, 'skills');
data = [];
array3.forEach(line => {
  if (line) {
    data.push(JsonUtil.toSkill(line));
  }
});
return this.db.batchSet(data, 'skills');

一切正常,数据保存在我的Firestore中。

我在for内使用do whileifforEach尝试了多种使之动态化的方法,但均无效果。所以这是我的问题。我是在做一些我在动态代码中看不到的愚蠢的事情,还是批处理写入本身带来了更深层次的问题?

让我知道你们是否需要更多我的代码,但我认为我提供的足够好。

在此先感谢并为我的英语写作不好而感到遗憾。

0 个答案:

没有答案