我正在尝试在调整一组图像大小时更新文档,以显示进度并跟踪是否有任何图像无法转换。
我们在 dir 中几乎没有图像,其中 dir 是文档 ID。使用文档 ID,我们必须更新该文档。我们必须设置状态字段,状态包含已转换或转换失败信息的对象。 {图像:路径,处理:字符串}
看起来像 { ... 地位 : [ 文件名1:{...}, 文件名2:{...} ] }
但是当我上传 5 到 10 个图像时,它只在状态字段中设置前 4-5 个图像信息。在将最后一个图像信息写入状态之前,它会暂停(或看起来像是暂停或覆盖一些信息)。
虽然我尝试简单地用状态中的新数据替换旧数据,但这意味着只有单个对象会出现在此处并相应地发生更改。这在大多数情况下都有效。我见过罕见的情况,这也失败了,但大多数时候它都有效。
还尝试拥有对象数组,但也错过了一些条目。
async function updateDoc({filePath, metadata}) {
const [docId, fileName] = filePath.split('/');
const db = admin.firestore();
const collectionRef = db.collection(COLLECTION_PACKS).doc(docId);
const stickersRef = collectionRef.collection(COLLECTION_STICKERS);
let attempts = 0;
const maxAttempts = 5;
while (attempts < maxAttempts) {
try {
await db.runTransaction(async (transaction) => {
const updatedStatus = {};
updatedStatus[fileName] = metadata;
// Update the document with the new status and progress
transaction.update(collectionRef, {
status: updatedStatus,
});
});
console.log("Updated document for", filePath);
break; // Exit the loop if successful
} catch (error) {
attempts++;
console.error(`Error updating document (attempt ${attempts}):`, error);
if (attempts >= maxAttempts) {
throw error; // Re-throw the error after max attempts
}
await new Promise(resolve => setTimeout(resolve, 1000 * attempts)); // Exponential backoff
}
}
}
async function updateMeta({filePath, process, valid, error}){
// console.log("updateMeta ",filePath)
let metadata = { process, valid }
if (error) { metadata.error = error; }
await bucket.file(filePath).setMetadata({
metadata: metadata
})
await updateDoc({ filePath, metadata})
}
无论是嵌套对象还是对象数组,两者都可以。
不需要使用
db.runTransaction()
,因为您没有在更新中使用任何旧值,因此它只是添加了更多不必要的处理。
如果您的数据结构实际上是
{ ... status : { filename1:{...}, filename2:{...} } }
(请注意,我用大括号替换了方括号,我相信您的意思是对象而不是数组),那么您可以简单地更新嵌套路径,而无需使用事务。也无需重试:
// this is a docRef, not a colRef as in your example
const docRef = db.collection(COLLECTION_PACKS).doc(docId);
const update = {
[`status.${fileName}`]: metadata,
};
await docRef.update(update);
====== 编辑:
进一步解释一下,当你说:
但是当我上传 5 到 10 个图像时,它只在状态字段中设置前 4-5 个图像信息。它在将最后一个图像信息写入状态之前暂停。
我不认为它会暂停。我相信你有竞争条件。请注意,您将覆盖每个文件上的整个
status
对象。这意味着如果文件按 1-2-3-4 的顺序触发,但它们完成处理 1-2-4-3,您最终将得到第三个文件的信息,而不是最后一个文件的信息。
这与您显示的代码不一致,但根据您所说的,如果您打算在更新之前获取整个 status
对象,那么这是可能的。