Firestore云函数用于操作集合

huangapple go评论137阅读模式
英文:

Firestore cloud function to manipulate collection

问题

I have two collections:
Db.collection(groups)
Db.collection(users)
The group doc stores a map of members.
Id like to fire a function which iterates over the collection, storing aggregated data from the user document (eg. Number activities last week)
How to handle this, if the collection contains many documents?

我有两个集合:
Db.collection(groups)
Db.collection(users)
群组文档存储了成员的映射。
我想触发一个函数,遍历集合,从用户文档中存储聚合数据(例如,上周的活动数量)。
如果集合包含许多文档,如何处理?

I would solve this with a promise. But i guess i run into limits of collection.get() or a timeout during the forEach loop.
Is a paginated read (.startAt()) the solution here? What about the timeout?

我会使用一个Promise来解决这个问题。但我猜想在forEach循环中会遇到collection.get()的限制或超时问题。
在这里,分页读取(.startAt())是解决方案吗?超时问题怎么解决?

export const someMethod = functions.https.onRequest((req, res) => {
    let stuff: any[] = [];
    let db = getFirestore();
    db.collection("groups").get().then(snapshot => {

        snapshot.forEach(doc => {
            var newelement = {
                "Members.${doc.id}.activities": doc.data().activities.length }
//batched write for every doc
// ...
 
        });
        res.send("ok")
        return "";
    }).catch(reason => {
        res.send(reason)
    })
});
export const someMethod = functions.https.onRequest((req, res) => {
    let stuff: any[] = [];
    let db = getFirestore();
    db.collection("groups").get().then(snapshot => {

        snapshot.forEach(doc => {
            var newelement = {
                "Members.${doc.id}.activities": doc.data().activities.length }
//批量写入每个文档
// ...
 
        });
        res.send("ok")
        return "";
    }).catch(reason => {
        res.send(reason)
    })
});
英文:

I have two collections:
Db.collection(groups)
Db.collection(users)
The group doc stores a map of members.
Id like to fire a function which iterates over the collection, storing aggregated data from the user document (eg. Number activities last week)
How to handle this, if the collection contains many documents?

I would solve this with a promise. But i guess i run into limits of collection.get() or a timeout during the forEach loop.
Is a paginated read (.startAt()) the solution here? What about the timeout?

export const someMethod = functions.https.onRequest((req, res) => {
    let stuff: any[] = [];
    let db = getFirestore();
    db.collection("groups").get().then(snapshot => {

        snapshot.forEach(doc => {
            var newelement = {
                "Members.${doc.id}.activities": doc.data().activities.lenth }
//batched write for every doc
// ...
 
        });
        res.send("ok")
        return "";
    }).catch(reason => {
        res.send(reason)
    })
});

答案1

得分: 0

在 Cloud Functions v1 中,单个函数调用最长可运行 9 分钟,而在 gen 2 中最长可运行 60 分钟。如果对于你的工作负载来说不够,你将不得不将其拆分成多个调用 - 例如,通过让你的主函数创建多个任务。

了解更多信息,请参考:

英文:

On Cloud Functions v1 a single function invocation can run up to 9 minutes, on gen 2 it can run up to 60 minutes. If that isn't enough for your workload, you will have to split it out over multiple invocations - for example by having your main function create a number of tasks.

For more on this, see:

答案2

得分: 0

你似乎在forEach之后返回并发送响应。这会导致函数在后台运行,不能保证在此点之后执行:

Cloud Functions故障排除

后台活动(在函数终止后发生的任何事情)可能会引发问题,因此请检查您的代码。Cloud Functions不保证在函数执行期间以外运行的任何操作,因此即使活动在后台运行,也可能会被清理过程终止。

你可能想在这里使用async/await语法。在forEach中使用的Promise不会按您想的方式执行。最好的方法是使用for..of遍历组。但是,batchWrites一次只允许500个操作,因此您需要一些逻辑来每次只获取500个操作。

// 由于Firestore批量写入限制为500,如果需要,将操作分成多个批次
const batches: WriteBatch[] = [];
let currentBatch = getFirestore().batch();
let operationCounter = 0;

for (const groupDoc of groupsSnapshot.docs) {
if (operationCounter === 500) {
batches.push(currentBatch);
currentBatch = getFirestore().batch();
operationCounter = 0;
}

const newElement = { [`Members.${groupDoc.id}.activities`]: 
groupDoc.data().activities.length };

// ... 将newElement添加到批量写操作
// 假设我们有一个文档引用,docRef
// currentBatch.update(docRef, newElement);

operationCounter++;

}
// 如果批次有操作,推送最后一个批次
if (operationCounter > 0) {
batches.push(currentBatch);
}

// 执行所有批量写入
const batchPromises = batches.map((batch) => batch.commit());

try {
await Promise.all(batchPromises);
return "ok";
} catch (error) {
return error;
}

英文:

You seem to be returning and sending back a response after the forEach. This will cause the function to run in the background which can't guarantee execution after this point:

https://cloud.google.com/functions/docs/troubleshooting

> Background activity (anything that happens after your function has terminated) can cause issues, so check your code. Cloud Functions does not guarantee any actions other than those that run during the execution period of the function, so even if an activity runs in the background, it might be terminated by the cleanup process.

You might want to use async/await syntax here. Promises within a forEach don't execute how you would think. Best bet would be to iterate with a for..of over the groups. However, batchWrites only allow 500 operations at a time, so you'll need some logic to slice(0, 500) to only get 500 operations at a time.

// Since Firestore batch write limit is 500, divide operations into 
multiple batches if needed
const batches: WriteBatch[] = [];
let currentBatch = getFirestore().batch();
let operationCounter = 0;

for (const groupDoc of groupsSnapshot.docs) {
    if (operationCounter === 500) {
  batches.push(currentBatch);
  currentBatch = getFirestore().batch();
  operationCounter = 0;
}

const newElement = { [`Members.${groupDoc.id}.activities`]: 
groupDoc.data().activities.length };

// ... add newElement to the batch write operation
// assuming we have a document reference, docRef
// currentBatch.update(docRef, newElement);

operationCounter++;
}
// Push the last batch if it has operations
if (operationCounter > 0) {
  batches.push(currentBatch);
}

// Execute all batch writes
const batchPromises = batches.map((batch) => batch.commit());

try {
  await Promise.all(batchPromises);
  return "ok";
} catch (error) {
  return error;
}

huangapple
  • 本文由 发表于 2023年5月18日 00:37:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76274347.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定