Reputation: 11
I using firebase and create trigger listen any change from student document. If student document change, i push any change to rest api. But my function call mutiple time.
Bellow is my function :
exports.triggerTimeStudent= functions.firestore
.document('users/{userId}/class/{classId}/students/{studentId}')
.onUpdate( (change, context) => {
const newValue = change.after.data();
const previousValue = change.before.data();
const {update_at: afterStatus} = newValue;
const {update_at: beforeStatus} = previousValue;
const {name: name} = newValue;
if (afterStatus !== beforeStatus) {
try {
var data = {
"student_name": name,
};
console.log(data);
console.log("Inside Rest API");
return rest.post("https://example.com/api/v1/student/add-by-name", {
...studentServiceRestOption, ...{
body: JSON.stringify(data)
}
});
} catch (error) {
return res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.send(buildError({
code: errorCode.SYSTEM_ERROR,
message: error.message,
}))
}
}
I can't know why function call mutiple time. I want call only time. My function incorrect. Please help
Upvotes: 0
Views: 45
Reputation: 26306
By design, Cloud Functions may be called multiple times. It is up to you to ensure that your functions can handle being retried.
However, your error likely stems from the value of the update_at
key. If this key's value is an object, the ===
and !==
operands aren't going to produce the correct result. You will need to check the object for an "isEqual" or "equals" method, or use a third-party solution such as _.isEqual
.
Below, I have refactored your code for performance and ease-of-use. I could not identify the rest
object you were using for the API call, so I have substituted it for node-fetch
.
const fetch = require("node-fetch"); // see https://www.npmjs.com/package/node-fetch
// for object equality tests
// const isEqual = require("lodash.isequal");
const STUDENT_SERVICE_DEFAULT_OPTIONS = {
method: "post",
headers: {
"Content-Type": "application/json"
}
}
exports.triggerTimeStudent= functions.firestore
.document("users/{userId}/class/{classId}/students/{studentId}")
.onUpdate( (change, context) => {
const beforeStatus = change.before.get("update_at"); // accessed directly for performance
const afterStatus = change.after.get("update_at");
// If beforeStatus and afterStatus are
// - string, boolean, int, etc.: use beforeStatus === afterStatus
// - firestore.Timestamp objects: use beforeStatus.isEqual(afterStatus)
// - custom objects: use isEqual(beforeStatus, afterStatus) from lodash/underscore packages
if (beforeStatus === afterStatus) {
console.log("Status unmodified. Ignored change.");
return;
}
const data = {
student_name: change.after.get("name")
}
console.log("Making API call...", { data });
const fetchOptions = {
...STUDENT_SERVICE_DEFAULT_OPTIONS,
body: JSON.stringify(data)
}
return fetch("https://example.com/api/v1/student/add-by-name", fetchOptions)
.then(response => {
if (!response.ok) { // see "Handling client and server errors" in "node-fetch" docs
throw new Error("Unexpected API response: " + response.statusText);
}
console.log("Successfully added student!");
})
.catch(error => console.error("Failed to add student!", { error, fetchOptions }));
});
Note: You can view the logged messages from Cloud Functions in the Firebase console.
Upvotes: 1