代码之家  ›  专栏  ›  技术社区  ›  Jonah

Firebase云函数对象更新创建递归

  •  1
  • Jonah  · 技术社区  · 6 年前

    我的应用程序有一个简单的云函数来跟踪创建/更新的时间戳。看起来是这样的:

    export const objectChanges = functions
      .firestore
      .document('objects/{id}')
      .onWrite(event => {
        const patch: {created_at?: string, updated_at: string} = {
          updated_at: <string> event.timestamp
        };
    
        if (!event.data.previous) {
          patch.created_at = event.timestamp;
        }
    
        return event.data.ref.set(patch, {merge: true});
      });
    

    只要我上传这个函数并在列表中创建/修改一个对象,它就会开始不断地勾选更新的\u。我猜它是在检测它自己对updated\u at字段所做的更改。考虑到文档中显示了此类更新的示例,这种行为让我感到困惑。

    https://firebase.google.com/docs/functions/firestore-events#writing_data

    我是否遗漏了细微差别,或者这是Firestore的bug?

    4 回复  |  直到 6 年前
        1
  •  4
  •   Vivek Athalye    6 年前

    如果您检查文档中给出的示例,则需要检查一个条件,以确定 name 已更改。如果是,则只执行以下代码。如果它没有改变,它只是 return s、 像这样:

    // We'll only update if the name has changed.
    // This is crucial to prevent infinite loops.
    if (data.name == previousData.name) return;
    

    因此,在您的情况下,您还需要检查对象的实际数据(除 updated_at )是否更改。如果没有其他(除了 更新位置:\u )如果已更改,则只需退出该函数即可。

        2
  •  2
  •   Doug Stevenson    6 年前

    请特别注意您引用的文档示例代码部分:

    // We'll only update if the name has changed.
    // This is crucial to prevent infinite loops.
    if (data.name == previousData.name) return;
    

    您需要找出一种方法来检测函数执行的更新何时在同一位置触发后续更新。

        3
  •  1
  •   Cooper Scott    3 年前

    在onUpdate触发器中,使用最新时间向文档添加或更新时间戳字段( admin.firestore.fieldValue.serverTimestamp() ). 对于本例,我将调用timestamp变量 time .

    这个 onUpdate 函数为您提供 before after 文件如果 before.time == after.time ,则您知道用户进行了更改。如果 before.time !== after.time ,您知道云功能发生了变化。

    if(snap.before.data().time !== snap.after.data().time){
       // The cloud function altered the document.
       // Return to prevent recursion!
       return;
    }
    

    当您从客户端更新文档时,还要更新 时间 具有最新时间的变量。这样,云函数就不会在执行所需代码之前终止。

        4
  •  0
  •   Jared Forth Lakshmanan Ganesan    4 年前

    当您编写一个由自身触发的函数,但只更改该updated\u at字段时,可以检查以前的updated\u at字段是否在新updated\u at字段的特定范围内。

    以下代码位于您的云函数中

    .onUpdate( async (change) => {
    
    })
    
    
    
    //exit if the last write happened within 5 seconds
    if(change.after.data().updated_at - change.before.data().updated_at <= 5) {
        return;
    }
    
            const date: Date = new Date();
    
            try {
                await db
                    .collection("collection_name")
                    .doc(change.after.id)
                    .set({ updated_at: date }, { merge: true });
            } catch (e) {
                functions.logger.log("failed updating doc in collection_name: ", e);
                return false;
            }
    
    return true;
    
    

    我用了5秒钟,因为 -我不在乎我更新的时间戳是否关闭了5秒 -我不确定在生产中延迟会有多长(这种情况也适用于1s,模拟器中的云功能大约每0.015 s运行一次)