Skip to content

Cloud Function – Part 2 : Background Functions

Firestore

// Specific
exports.myFunctionName = functions.firestore
    .document('users/marie').onWrite((change, context) => {
      // ... Your code here
    });


// Or group
exports.useWildcard = functions.firestore
    .document('users/{userId}')
    .onWrite((change, context) => {

      // If we set `/users/marie` to {name: "Marie"} then
      // context.params.userId == "marie"
      // ... and ...
      // change.after.data() == {name: "Marie"}

    });

4 events :

onCreateTriggered when a document is written to for the first time.
onUpdateTriggered when a document already exists and has any value changed.
onDeleteTriggered when a document with data is deleted.
onWriteTriggered when onCreateonUpdate or onDelete is triggered.

Context Gồm :

const authVar = context.auth; // Auth information for the user.

const authType = context.authType; // Permissions level for the user.

const pathId = context.params.id; // The ID in the Path.

const eventId = context.eventId; // A unique event ID.

const timestamp = context.timestamp; // The timestamp at which the event happened.

const eventType = context.eventType; // The type of the event that triggered this function.

const resource = context.resource; // The resource which triggered the event.

Create / Update / Delete

exports.createUser = functions.firestore
    .document('users/{userId}')
    .onCreate((snap, context) => {
      const newValue = snap.data(); // {'name': 'Marie', 'age': 66}
    });

exports.updateUser = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {

      const newValue = change.after.data(); // {'name': 'Marie', 'age': 66}
      const previousValue = change.before.data();

    });

exports.deleteUser = functions.firestore
    .document('users/{userID}')
    .onDelete((snap, context) => {
      const deletedValue = snap.data(); // {'name': 'Marie', 'age': 66}
    });
exports.modifyUser = functions.firestore
    .document('users/{userID}')
    .onWrite((change, context) => {
      // Get an object with the current document value.
      // If the document does not exist, it has been deleted.
      const document = change.after.exists ? change.after.data() : null;

      // Get an object with the previous document value (for update or delete)
      const oldDocument = change.before.data();
    });

Write Data

Cho phép sử dụng DocumentReference (ref) cũng với update()set(), &remove()

// Listen for updates to any `user` document.
exports.countNameChanges = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {

      // Then return a promise of a set operation to update the count
      return change.after.ref.set({
        name_change_count: count + 1
      }, {merge: true});
    });

Limit

Có thể mất đến 10s để exec task trong Cloud Firestore

Không có order

Lưu ý khi sử dụng onUpdate() trên Firestore & Realtime-DB

export const onMessageUpdate = functions.database
 .ref('/rooms/{roomId}/messages/{messageId}')
 .onUpdate((change, context) => {
    const before = change.before.val();
    const after = change.after.val();

    if (before.text === after.text) {
        console.log("text did not change");
        return null;
    }

    return change.after.ref.update({
        text: `edited text : ${after.text}`
    })
})

Nếu không chặn lại thì nó sẽ lặp mãi mãi ở đây

Tránh Race-Condition

Solution

Firebase Authentication

onCreate()exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => {
const email = user.email;
const displayName = user.displayName;
});
onDelete()exports.sendByeEmail = functions.auth.user().onDelete((user) => {
  // …
});

user gồm :

  • displayName
  • email
  • disabled(boolean)
  • emailVerified(boolean),
  • metadata
  • phoneNumber
  • photoURL
  • providerData
  • uid

Storage

onArchive 
Khi object chuyển (live -> archived) version hoặc overwrite bởi 1 object cùng tên khác
onDelete Khi 1 object bị xóa hoàn toàn (gồm overwrite)
*Không bị khi object Archive
onFinalize Khi 1 object mới add (gồm copy & rewrite existed object)
onMetadataUpdate Khi file đổi metadata
exports.generateThumbnail = functions.storage.object().onFinalize(async (object) => {

  const fileBucket = object.bucket; // The Storage bucket that contains the file.
  
  const filePath = object.name; // File path in the bucket.
  
  const contentType = object.contentType; // File content type.
  
  const metageneration = object.metageneration; // Number of times metadata has been generated. New objects have a value of 1.
  
});

Download -> Transform -> Upload File

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp()
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');

// Download file from bucket.
const bucket = admin.storage().bucket(fileBucket);
const tempFilePath = path.join(os.tmpdir(), fileName);
const metadata = {
  contentType: contentType,
};

await bucket.file(filePath).download({destination: tempFilePath});
console.log('Image downloaded locally to', tempFilePath);

// Generate a thumbnail using ImageMagick.
await spawn('convert', [tempFilePath, '-thumbnail', '200x200>', tempFilePath]);
console.log('Thumbnail created at', tempFilePath);


// We add a 'thumb_' prefix to thumbnails file name. That's where we'll upload the thumbnail.
const thumbFileName = `thumb_${fileName}`;
const thumbFilePath = path.join(path.dirname(filePath), thumbFileName);


// Uploading the thumbnail.
await bucket.upload(tempFilePath, {
  destination: thumbFilePath,
  metadata: metadata,
});


// Once the thumbnail has been uploaded delete the local file to free up disk space.
return fs.unlinkSync(tempFilePath);
Published inCloud Function

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *