Firebase Cloud functions. Multiple functions inside one schedule function - javascript

I need to run a function every 5 minutes that will fetch data from RSS and add it to firebase.
I currently have the following code:
exports.subscribeRss = functions.pubsub.schedule('every 5 minutes')
.onRun(async () => {
try {
const documents = await parseRssFeed(RSS_URL);
const preparedDocuments = prepareRssFeedData(documents);
await uploadBatchDocuments({
documents: preparedDocuments,
collection: 'documents'
});
} catch (error) {
console.error(new Error(error?.message));
}
});
But the problem is that every 5 minutes I need to load data from several RSS sources, and not from one, and also add them to firebase. There may be 10 or more. Can you please advise, how can I better organize such logic? To avoid code like this)
exports.subscribeRss = functions.pubsub.schedule('every 5 minutes')
.onRun(async () => {
try {
const documents = await parseRssFeed(RSS_URL);
const preparedDocuments = prepareRssFeedData(documents);
await uploadBatchDocuments({
documents: preparedDocuments,
collection: 'documents'
});
const documentsSecond = await parseRssFeed(RSS_URL_SECOND);
const preparedDocumentsSecond = prepareRssFeedData(documentsSecond);
await uploadBatchDocuments({
documents: preparedDocumentsSecond,
collection: 'documents'
});
} catch (error) {
console.error(new Error(error?.message));
}
});

Related

How to use mongoose updateMany middleware to increase performance?

SOLVED: SOLUTION AT THE BOTTOM
I have the following Code where I am updating element by element:
//registerCustomers.js
const CustomerRegistrationCode = require("../models/CustomerRegistrationCode");
const setRegCodesToUsed = async (regCodes) => {
for (let regCode of regCodes) {
await setRegCodeToUsed(regCode._id);
}
};
const setRegCodeToUsed = async (id) => {
await CustomerRegistrationCode.findByIdAndUpdate(id, { used: true });
};
The Code works fine but is to slow and i want to update many (1000) CustomerRegistrationCodes at once.
I had a look at the updateMany middleware function but found not much info online and on the official docs. I changed my code to the following but don't know how further.
//registerCustomers.js
const setRegCodesToUsed = async (regCodes) => {
await CustomerRegistrationCode.updateMany(regCodes);
}
//CustomerRegistrationCode.js
CustomerRegistrationCodeSchema.pre('updateMany', async function (next, a) {
console.log('amount arguments: ', arguments.length); //is 2
console.log(arguments); //both parameters are functions.
next();
});
What would be the best way to update many CustomerRegistrationCodes with 1000 different id's?
SOLUTION, thanks to Murat Colyaran
const setRegCodesToUsed = async (regCodes) => {
const ids = [];
regCodes.map(code => ids.push(code._id));
await setRegCodeToUsed(ids);
};
const setRegCodeToUsed = async (ids) => {
await CustomerRegistrationCode.updateMany(
{ _id: { $in: ids } },
{ used: true }
);
};
This should work:
//registerCustomers.js
const CustomerRegistrationCode = require("../models/CustomerRegistrationCode");
const setRegCodesToUsed = async (regCodes) => {
let ids = [];
regCodes.map((code) => ids.push(code._id.toString()));
await setRegCodeToUsed(ids);
};
const setRegCodeToUsed = async (ids) => {
await CustomerRegistrationCode.updateMany(
{
id : { $in: ids }
},
{
used: true
}
);
};
Instead of sending a query for every records, we just parse the id and send a bulk request with $in

Await New Promise Not Working When Getting Url Photo From Firebase Storage

I Want to get data contacts from firebase store and then get photo of contacts from firestore storage.
get_contact = async () => {
let contacts = [];
let campaignsRef = await firestore().collection('users').doc(global.iduser).collection("contacts").get();
for (let campaign of campaignsRef.docs) {
let tasksRef = firestore().collection('users').doc(campaign.data().uid).get();
await tasksRef
.then(DocumentSnapshot => {
let data = DocumentSnapshot.data();
let photo = new Promise((resolve, reject) => {
storage()
.refFromURL('gs://think-ce51b.appspot.com/profiledefault.jpg')
.getDownloadURL()
.then(url => {
resolve(url);
})
.catch(error => {
return reject(error);
});
});
console.log(photo);
contacts.push({
'key': data.uid,
'fullname': data.fullname,
'profilephoto': photo,
});
})
.catch(error => {
setInitializing(false);
});
}
setdataContacts(contacts);
setInitializing(false);}
I Can get data contacts from DocumenSnapshot. But when I want get url from firebase storage, photo return null/{"_U": 0, "_V": 0, "_W": null, "_X": null}. I think new promise in varible photo not function correctly.
How I can push to contacts only after photo get url?
There are quite a few problems with your code. The ones I quickly spotted:
The getDownloadURL method already returns a promise, so you don't need to create your own.
You should not mix await and then in code. Unless you intricately know what you're doing, it's best to stick to one or the other.
If we fix these two problems in your code, we end up with:
get_contact = async () => {
let contacts = [];
let campaignsRef = await firestore().collection('users').doc(global.iduser).collection("contacts").get();
for (let campaign of campaignsRef.docs) {
let tasksDoc = await firestore().collection('users').doc(campaign.data().uid).get();
let data = tasksDoc.data();
let url = await storage()
.refFromURL('gs://think-ce51b.appspot.com/profiledefault.jpg')
.getDownloadURL()
contacts.push({
'key': data.uid,
'fullname': data.fullname,
'profilephoto': photo,
});
}
setdataContacts(contacts);
setInitializing(false);
}
There may be more problems with the code, but this is a good starting point.

How can I update an array field with a batch write operation in firestore?

I've been trying to update an array of maps in my document while creating a new document in a sub-collection but couldn't make it work:
export const addTask = async (data, caseId) => {
let batch = await db.batch();
const caseRef = db.collection("cases").doc(caseId);
const taskRef = caseRef.collection("tasks").doc();
try {
await batch.set(taskRef, data);
await batch.set(caseRef, {
tasks: db.FieldValue.arrayUnion(data),
}, {merge:true});
} catch (error) {
console.log(error);
}
return batch.commit();
};
These are the issues:
use batch.update on the second batch call if the array field already exists on the parent doc and just needs to be updated.
FieldValue.arrayUnion isn't a method on the client instance of firestore. Use firebase.firestore.FieldValue.arrayUnion from the global firebase namespace to update the array. Check the guide on updating arrays
{merge:true} is not required as arrayUnion will add data to the existing set unless it already exists.
export const addTask = async (data, caseId) => {
let batch = await db.batch();
const caseRef = db.collection("cases").doc(caseId);
const taskRef = caseRef.collection("tasks").doc();
try {
await batch.set(taskRef, data);
await batch.update(caseRef, {
tasks: firebase.firestore.FieldValue.arrayUnion(data),
});
}catch (error) {
console.log(error);
}
return batch.commit();
}

Firestore join foreach map - get data from two collections

Hey Guys i need your help one more :(
I dont know how I make a Join or something else in Firebase
I have two collections:
collection("guests") has a datafield "Eventid" and a datafield "Userid"
in the first step i select all guests with a specific Userid. So i get all Eventids in a foreach loop (or as an Array)! In the second Collection
collection('events') I select all Information and write it in a JSON File. This works too after a couple of time and this is my problem!
I run this in a funktion and the function return before the Events were loaded.
I dont know how i use it i tried it with await and async or split it in two functions.
Maybye there is another way to realize it.
db.collection("guests").where("userid", "==", id).get().then(function(querySnapshot) {
querySnapshot.forEach(function (doc) {
db.collection('events').doc(doc.data().eventid).get().then(function(doc) {
if (doc.exists) {
console.log(doc.id, " => ", doc.data());
} else {
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
});
});
i got it!
exports.getEvent = functions.https.onRequest(async (req, res) => {
console.log('==NACHEINANDER STARTEN==');
const id = req.query.uid;
var arr = [];
var json = [];
let query = db.collection("guests").where("userid", "==", id);
await query.get().then(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
arr.push(documentSnapshot.data());
});
});
//console.log(arr);
await processArray(arr)
async function delayedLog(item) {
await db.collection('events').doc(item.eventid).get().then(function(doc) {
console.log(doc.data());
json.push(doc.data());
})
}
async function processArray(array) {
const promises = array.map(delayedLog);
// wait until all promises are resolved
await Promise.all(promises);
console.log('Done!');
}
console.log("hello");
res.status(200).send(JSON.stringify(json)); //, ...userData
});

HTTP Function ends with code 16, documents not updating

I have a function that returns the result correctly with: response.send("Update Last Payments Completed"); but in the log it reports: and no documents are updated
Error: Process exited with code 16
Here is my code:
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
/// Updates the last payment done in the neighbors documents
export const updateLastPaymentHTTP = functions.https.onRequest(
async (request, response) => {
try {
const neighbors = await admin.firestore().collection("neighbors").get();
const promises = [];
neighbors.forEach(async (neighbor) => {
const topPayment = await admin
.firestore()
.collection(`neighbors/${neighbor.ref}/payments`)
.orderBy("date", "desc")
.limit(1)
.get();
topPayment.forEach(async (payment) => {
if (payment.exists) {
const lastPayment = payment.data().date;
promises.push(neighbor.ref.update({ last_payment: lastPayment }));
} else {
promises.push(neighbor.ref.update({ last_payment: null }));
}
});
await Promise.all(promises);
response.send("Update Last Payments Completed");
});
} catch (error) {
console.log(`Error Updating Last Payment and Debt ${error}`);
}
}
);
Thanks in advance
You're calling response.send() inside a loop. That's almost certainly not what you want, as you can only send a single response, and then the function terminates. Move the last await and response.send() outside the loop. to be executed only a single time after all the work is complete.
neighbors.forEach(async (neighbor) => {
// ...
});
await Promise.all(promises);
response.send("Update Last Payments Completed");

Categories