Firebase cloud functions multiple transactions in one function? - firebase

I am trying to create a cloud function that executes two transactions at once.
I have tried to do the following, only the first transaction executes... When I add the second it doesn't work and I get no errors.
Function:
exports.followIncrement = functions.database
.ref("/followers/{userId}").onCreate((snapshot, context) => {
const userId = context.params.userId;
const currentUserUid = Object.keys(snapshot.val())[0];
console.log(currentUserUid);
console.log(userId);
var followerCount =
admin.database().ref('users').child(userId).child('followerCount')
var followingCount =
admin.database().ref('users').child(currentUserUid).child('followingCount')
return followerCount.transaction((currentCount) => {
return currentCount || 0 + 1;
})
.then(() => {
return followingCount.transaction((currentCount) => {
return currentCount || 0 + 1;
})
})
})
I appreciate all the feedback!
Cheers.

What happens if you do something like:
return followerCount.transaction((currentCount) => {
return currentCount || 0 + 1;
})
.then((count) => {
if (count.committed) {
return followingCount.transaction((currentCount) => {
return currentCount || 0 + 1;
})
}
})

Related

How can i skip first nth documents in Firestore? [duplicate]

This question already has answers here:
Firestore pagination by offset
(3 answers)
Is it possible to use an offset and limit by cloud_firestore?
(2 answers)
Closed 8 months ago.
I am working on pagination in vue and firebase and it is working fine. But now i want to go directly to the nth page using pagination. But firebase doesn't allow me to do that. Please guide me on how can fix this.
onMounted(() => {
totalLength()
if (lastDoc.value && currentPosition.value == 'next') {
next()
} else if (lastDoc.value && currentPosition.value == 'prev') {
prev()
} else {
loadPapers()
}
})
const next = () => {
savedTopifyPapers
.orderBy('timeStamp', 'asc')
.startAfter(lastDoc.value)
.limit(1)
.onSnapshot((snapshot) => {
lastDoc.value = snapshot.docs[snapshot.docs.length - 1]
if (snapshot.empty) {
loadingData.value = false
}
papersData.value = snapshot.docs.map((doc) => {
const data = doc.data()
const id = doc.id
loadingData.value = false
return { id, ...data }
})
papersDataLength.value = papersData.value.length
})
}
const prev = () => {
savedTopifyPapers
.orderBy('timeStamp', 'asc')
.endBefore(lastDoc.value)
.limit(1)
.onSnapshot((snapshot) => {
lastDoc.value = snapshot.docs[snapshot.docs.length - 1]
if (snapshot.empty) {
loadingData.value = false
}
papersData.value = snapshot.docs.map((doc) => {
const data = doc.data()
const id = doc.id
loadingData.value = false
return { id, ...data }
})
papersDataLength.value = papersData.value.length
})
}
const totalLength = () => {
savedTopifyPapers.get().then((response) => {
totalPaperLength.value = response.docs.length
})
}
const loadPapers = () => {
let t = savedTopifyPapers.orderBy('timeStamp', 'asc').limit(1)
console.log(lastDoc.value)
if (lastDoc.value) {
t = savedTopifyPapers.startAfter(lastDoc.value)
}
t.onSnapshot((snapshot) => {
console.log(snapshot.empty)
const _lastDoc = snapshot.docs[snapshot.docs.length - 1]
if (_lastDoc) {
lastDoc.value = _lastDoc
}
if (snapshot.empty) {
loadingData.value = false
}
papersData.value = snapshot.docs.map((doc) => {
const data = doc.data()
const id = doc.id
loadingData.value = false
return { id, ...data }
})
papersDataLength.value = papersData.value.length
})
}
Any solution appreciated!

Firebase returning undefinfed

I keep getting a response undefined with the return function. After a second the console.log displays the information. My guess is that the data is still being gathered and that the function is already returning. I thought it would be solved with a promise but it has not. What am I missing? why is my function returning without any data?
TakenSpaces = 0
let startDate = new Date(time)
startDate.setHours(0)
startDate.setMinutes(0)
let endDate = new Date(startDate)
endDate.setHours(24)
data = []
const reservations = db.collection('organisation').doc('Amigos').collection('reservations')
.where('start', '>=', startDate)
.where('start', '<=', endDate).get()
console.log('promse made')
reservations.then((docs) => {
// console.log(docs.data())
// return docs.data()
// const promises = []
docs.forEach((doc) => {
data.push(doc.id)
})
// console.log(data)
// console.log('DONE TESTING')
return data
// return Promise.all(promises)
})
.then((test) => { console.log(test); return test })
// for (const reservation of reservations) {
// console.log(reservation)
// }
// .then((docs) => {
// // for (const doc of docs) {
// // console.log(doc.id)
// // }
// docs.forEach((doc) => {
// if (doc.data().people){
// const people = doc.data().people
// TakenSpaces = TakenSpaces + people
// }
// // console.log(doc.data().people)
// });
// return TakenSpaces
// })
// return TakenSpaces
}
const t = getTakenCapacity(time)
console.log(t)
It works know. But If anyone knows if the function can only return when everything is finished and not have to return a promise function.
function getTakenCapacity (time) {
TakenSpaces = 0
let startDate = new Date(time)
startDate.setHours(0)
startDate.setMinutes(0)
let endDate = new Date(startDate)
endDate.setHours(24)
data = []
const reservations = db.collection('organisation').doc('Amigos').collection('reservations')
.where('start', '>=', startDate)
.where('start', '<=', endDate).get()
return reservations.then((docs) => {
// console.log(docs.data())
// return docs.data()
// const promises = []
var dd = new Array
docs.forEach((doc) => {
data.push([[time], doc.data().people])
})
// console.log(data)
// console.log('DONE TESTING')
return data
// return Promise.all(promises)
})
getTakenCapacity(time).then(function(result) {
console.log(result) // "Some User token"
})

How to avoid promise nesting

I have a feeling I'm doing an overkill nesting in the following simple function, which simply reads a value from one location and writes it to another location.
Is there a way to simplify it somehow?
exports.myFunc = functions.database.ref('...').onCreate(event => {
const list_id = event.params.list_id;
return new Promise(function(resolve, reject){
event.data.adminRef.root.child('lists').child(list_id).child('owner').once('value').then(function(snap){
const owner_id = snap.val();
if (owner_id != null) {
event.data.adminRef.root.child('users').child(owner_id).child('whatever').child('whatever2').set(true)
.then(function() {
resolve();
},
function(err) {
reject();
}
)
} else {
reject();
}
});
});
})
You don't need a new promise if you have existing promises to work with. You can return promises from then to continue chaining.
exports.myFunc = functions.database.ref('...').onCreate(event => {
const list_id = event.params.list_id;
return event.data.adminRef.root.child('...').once('value')
.then(function(snap){
const owner_id = snap.val();
if (owner_id != null) {
return event.data.adminRef.root.child('...').set(true)
} else {
return Promise.reject('error message')
}
});
})

Cloud functions for firebase with transaction operation finished with status: 'timeout'

Function with transaction operation is timing out. I am not able find out what is wrong. I am not sure if it is an issue with firebase.
exports.ComputeUserReviews = functions.database.ref("/reviews/{userid}/{jobid}").onWrite((event) => {
const userid = event.params.userid;
const parentRefPromise = admin.database().ref(`reviews/${userid}`).once('value');
const UserReviewRef = admin.database().ref(`users/${userid}/account`);
return Promise.all([parentRefPromise]).then(results => {
const userReviewSnapshot = results[0];
const hasreviewPromise = UserReviewRef.child("hasreview").transaction(current => {
if (userReviewSnapshot.numChildren() === 0) {
return false;
} else if (userReviewSnapshot.numChildren() > 0) {
return true;
}
});
const reviewcountPromise = UserReviewRef.child("reviewcount").transaction(current => {
if (event.data.exists() && !event.data.previous.exists()) {
return (current || 0) + 1;
} else if (!event.data.exists() && event.data.previous.exists()) {
return (current || 0) - 1;
}
});
return Promise.all([hasreviewPromise, reviewcountPromise]);
});
});
There is an issue with the firebase SDK, as a workaround adding .then(()=>{console.log('message');}); fix the timeout.
const reviewcountPromise = UserReviewRef.child("reviewcount").transaction(current => {
if (event.data.exists() && !event.data.previous.exists()) {
return (current || 0) + 1;
} else if (!event.data.exists() && event.data.previous.exists()) {
return (current || 0) - 1;
}
}).then(()=>{console.log('message');});

Cloud Functions for Firebase return array of promises to GCF

In my onWrite event handler I perform data updates in different database paths. The function gets interrupted without finishing performing tasks. I am implementing Promise.all() to send array of promises to GCF and await for all outstanding work/tasks to complete. Console log is not showing errors. I am trying to find out if I am doing the right implementation.
exports.ObserveProposals = functions.database.ref("/proposals/{jobid}/{propid}").onWrite((event) => {
const jobid = event.params.jobid;
const userId = event.params.propid;
const promises = [];
const isinvitation = event.data.child("isinvitation").val();
if (!isinvitation) {
return userRef = admin.database().ref(`users/${userId}/proposals/sent`);
if (event.data.exists() && !event.data.previous.exists()) {
return userRef.child(jobid).set({
timestamp: admin.database.ServerValue.TIMESTAMP
});
} else if (!event.data.exists() && event.data.previous.exists()) {
return userRef.child(jobid).remove();
}
promises.push(userRef);
}
return collectionRef = admin.database().ref(`/jobs/${jobid}`).once('value').then(snapshot => {
if (snapshot.val() !== null) {
return countRef = collectionRef.child("proposals").transaction(current => {
if (event.data.exists() && !event.data.previous.exists()) {
return (current || 0) + 1;
} else if (!event.data.exists() && event.data.previous.exists()) {
return (current || 0) - 1;
}
});
}
promises.push(collectionRef);
});
return Promise.all(promises);
});
Bellow function is working properly, array of promises is being sent to GCF and all tasks are executed.
exports.ObserveProposals = functions.database.ref("/proposals/{jobid}/{propid}").onWrite((event) => {
const jobid = event.params.jobid;
const userid = event.params.propid;
const promises = [];
let userRef = admin.database().ref(`users/${userid}/proposals`);
let jobRef = admin.database().ref(`/jobs/${jobid}/proposals`);
jobRef.once('value').then(snapshot => {
if (snapshot.val() !== null) {
jobRef.transaction(current => {
if (event.data.exists() && !event.data.previous.exists()) {
return (current || 0) + 1;
} else if (!event.data.exists() && event.data.previous.exists()) {
return (current || 0) - 1;
}
});
}
});
promises.push(jobRef);
if (event.data.exists() && !event.data.previous.exists()) {
const isInvitation = event.data.child("isinvitation").val();
if (!isInvitation) {
return userRef.child(`/sent/${jobid}`).set({
timestamp: admin.database.ServerValue.TIMESTAMP
});
} else if (isInvitation) {
return userRef.child(`/received/${jobid}`).set({
timestamp: admin.database.ServerValue.TIMESTAMP
});
}
} else if (!event.data.exists() && event.data.previous.exists()) {
const isInvitation = event.data.previous.child("isinvitation").val();
if (!isInvitation) {
return userRef.child(`/sent/${jobid}`).remove();
}else if (isInvitation) {
return userRef.child(`/received/${jobid}`).remove();
}
}
promises.push(userRef);
return Promise.all(promises);
});

Resources