Skip to content

event.data undefined in onDocumentWritten when migrating from V1 to V2 API #1659

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
tharropoulos opened this issue Jan 7, 2025 · 4 comments

Comments

@tharropoulos
Copy link

Related issues

#1464, but we measured the size of the responses and it does not exceed the 10MB threshold discussed in that issue.

[REQUIRED] Version info

node: v18.20.4

firebase-functions: 6.1.1

firebase-tools: 13.28.0

firebase-admin: 13.0.1

[REQUIRED] Test case

typesense/firestore-typesense-search#98

[REQUIRED] Steps to reproduce

When migrating from Firebase Functions v1 to v2 API, specifically from functions.firestore.document().onWrite() to onDocumentWritten(), the event.data property is coming back as undefined.

The existing V1 implementation of our backfill function:

const functions = require("firebase-functions");

const validateBackfillRun = (snapshot) => {
  if (![true, "true"].includes(snapshot.after.get("trigger"))) {
    functions.logger.error("Skipping backfill. `trigger: true` key was not found");
    return false;
  }

  const collectionsToSync = snapshot.after.get("firestore_collections");
  if (Array.isArray(collectionsToSync) && !collectionsToSync.includes(config.firestoreCollectionPath)) {
    functions.logger.error("Collection not in firestore_collections array");
    return false;
  }

  return true;
};

module.exports = functions.firestore.document(triggerPath).onWrite(async (snapshot, context) => {
  if (!validateBackfillRun(snapshot)) {
    return false;
  }
  // Rest of the function
});

Migrating over to the V2 API:

const {onDocumentWritten} = require("firebase-functions/v2/firestore");
const {error} = require("firebase-functions/logger");

const validateBackfillRun = (snapshot) => {
  if (![true, "true"].includes(snapshot.after.get("trigger"))) {
    error("Skipping backfill. `trigger: true` key was not found");
    return false;
  }

  const collectionsToSync = snapshot.after.get("firestore_collections");
  if (Array.isArray(collectionsToSync) && !collectionsToSync.includes(config.firestoreCollectionPath)) {
    error("Collection not in firestore_collections array");
    return false;
  }

  return true;
};

module.exports = onDocumentWritten(triggerPath, async (event) => {
  // event.data is undefined here
  if (!validateBackfillRun(event.data)) {
    return false;
  }
  // Rest of the function
});

Will result in functionality breaking, as event.data comes back as undefined.

Here's the commit and diff in question.

[REQUIRED] Expected behavior

Returning the data object

[REQUIRED] Actual behavior

event.data is undefined.

Were you able to successfully deploy your functions?

Did not deploy, caught in CI. The PR posted includes both a description of the changes and the test failure.

@i14h
Copy link
Member

i14h commented Jan 21, 2025

@taeold Daniel can you kindly look into this? The Typesense extension team is running into this while migrating to v2.

@taeold
Copy link
Contributor

taeold commented Jan 21, 2025

@tharropoulos thanks for reporting! Can you share how you are testing the change?

I mention that you didn't deploy this change, which make sense - there isn't a way to seemlessly upgrade your v1 functions to v2 function without downtime.

See https://firebase.google.com/docs/functions/2nd-gen-upgrade

@tharropoulos
Copy link
Author

@taeold Thanks for the quick reply! Let me clarify our testing setup and migration process:

We're testing this using Firebase Emulators with Jest. Here's our testing flow:

  1. We have three test suites that run using firebase emulators:exec:
"test-part-1": "firebase emulators:exec --only functions,firestore,extensions 'jest --testRegex=\"WithFlattening\" --testRegex=\"backfill.spec\"'"
  1. The test creates Firestore documents and verifies they sync correctly to Typesense. Here's a sample test:
const book = {
  author: "Author A",
  title: "Title X",
  country: "USA",
};
const firestoreDoc = await firestore.collection(config.firestoreCollectionPath).add(book);
  1. When console logging the event in our v2 function implementation, we see:
{ 
  value: { 
    name: 'projects/ts-integration-aaf0c/databases/(default)/documents/books/xnx6fXYuOhKFJTCK2gq3', 
    fields: { 
      author: { stringValue: 'Author A' }, 
      title: { stringValue: 'Title X' }, 
      country: { stringValue: 'USA' } 
    }, 
    createTime: '2025-01-22T07:33:05.633271Z', 
    updateTime: '2025-01-22T07:33:05.633271Z' 
  }, 
  updateMask: {}, 
  params: {}, 
  data: undefined 
}

So when accessing the after property on event.data, we get an undefined reference error.

The key issue is we expected event.data to contain the DocumentSnapshot like in v1, but it's undefined in v2. Looking at the upgrade guide, we see the event structure has changed, but we're not able to properly access the data in v2 when using the emulator.

Is there a different way we should be accessing the document data in v2? Or do we need to adjust our emulator testing setup to properly support v2 functions?

@tharropoulos
Copy link
Author

Closing this, we didn't format the resources correctly in our extension.yaml, that's why the emulators weren't picking up on the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants