因此,当我将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中的数据。 linesArray
和JsonUtil.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 while
,if
和forEach
尝试了多种使之动态化的方法,但均无效果。所以这是我的问题。我是在做一些我在动态代码中看不到的愚蠢的事情,还是批处理写入本身带来了更深层次的问题?
让我知道你们是否需要更多我的代码,但我认为我提供的足够好。
在此先感谢并为我的英语写作不好而感到遗憾。