how to check if email already exist in firestore collection - firebase

im trying to check if the user already exists in the collection and at this point i don't even know what to do. Please help me, here is my code so far.
const Form = () => {
const [email, setEmail] = useState({});
const [name, setName] = useState({});
async function getEmail() {
const emailUserQuery = query(
collection(store, "emails"),
where("email", "==", true ),
limit(1)
);
// const querySnapshot = await getDocs(emailUserQuery);
onSnapshot(emailUserQuery, (QuerySnapshot => {
QuerySnapshot.forEach((snap) => {
console.log(
snap.id, "=>", snap.data()
);
});
}))
}
};
export default Form;

Make sure to pass the email address you're lookng for to the where clause:
async function emailAlreadyExists(email) {
const db = getFirestore();
const querySnapshot = await getDocs(query(
collection(db, "emails"),
where("email", "==", email),
limit(1)
));
return !querySnapshot.empty
}

Related

How to get all items from subcollection Firebase Firestore Vue

How do I get all the comments from the subcollection?
This is mine reusable function to get comments collection.
import { ref, watchEffect } from 'vue';
import { projectFirestore } from '../firebase/config';
const getCollection = (collection, id, subcollection) => {
const comments = ref(null);
const error = ref(null);
// register the firestore collection reference
let collectionRef = projectFirestore
.collection(collection)
.doc(id)
.collection(subcollection);
const unsub = collectionRef.onSnapshot(
snap => {
let results = [];
snap.docs.forEach(doc => {
doc.data().createdAt && results.push(doc.data());
});
// update values
comments.value = results;
error.value = null;
},
err => {
console.log(err.message);
comments.value = null;
error.value = 'could not fetch the data';
}
);
watchEffect(onInvalidate => {
onInvalidate(() => unsub());
});
return { error, comments };
};
export default getCollection;
And this is mine Comments.vue where i passing arguments in setup() function (composition API)
const { comments } = getAllComments('posts', props.id, 'comments');
When i console.log(comments) its null, in snapshot doc.data() is good but somehow results too is empty array even if i push doc.data() to results array and pass it to comments.value.
Can someone help me how to get that subcollection?
This is my Comment.vue component
export default {
props: ['id'],
setup(props) {
const { user } = getUser();
const content = ref('');
const { comments } = getAllComments('posts', props.id, 'comments');
const ownership = computed(() => {
return (
comments.value && user.value && user.value.uid == comments.value.userId
);
});
console.log(comments.value);
}
return { user, content, handleComment, comments, ownership };
},
};
const getCollection = (collection, id, subcollection) => {
const comments = ref(null);
const error = ref(null);
// Firestore listener
return { error, comments };
}
The initial value of comments here is null and since Firebase operations are asynchronous, it can take a while before the data loads and hence it'll log null. If you are using comments in v-for then that might throw an error.
It'll be best if you set initial value to an empty array so it'll not throw any error while the data loads:
const comments = ref([]);
Additionally, if you are fetching once, use .get() instead of onSnapshot()

SendGrid template transactional v3 functions Firebase

I am using a function in Firebase to send an email every time there is a new record in Firestore, this worked fine, but it seems that SendGrid has been updated to a new version of transactional templates.
What I had before in the body of my SendGrid transaction template was:
nombre: {{nombre}}
email: {{email}}
celular: {{celular}}
valorPropiedad: {{valorPropiedad}}
This worked correctly, that is, it sent the mail (every time there was a new record in Firestore) with the data of the new record, but now it only sends the mail but arrives without any data. I think something has changed in SendGrid? or is it a theme of my function?
Before I used Angular 5 I am now using version 6.
Here the code of my function index.js:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const SENDGRID_API_KEY = functions.config().sendgrid.key
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);
exports.firestoreEmail2 = functions.firestore
.document('domiciliarios/{domiciliarioId}')
.onCreate((snap, context) => {
const domiciliarioId = context.params.domiciliarioId;
const db = admin.firestore()
return db.collection('domiciliarios').doc(domiciliarioId)
.get()
.then(doc => {
const domiciliario = doc.data();
const msg = {
from: 'mail1#mail.com',
to: 'mail2#mail.com',
subject: 'mySubject',
templateId: 'myTemplateId',
substitutionWrappers: ['{{', '}}'],
substitutions: {
nombre: domiciliario.nombre,
email: domiciliario.email,
celular: domiciliario.celular,
valorPropiedad: `US$ ${domiciliario.valorPropiedad}`,
}
};
return sgMail.send(msg)
})
.then(() => console.log('email sent!'))
.catch(err => console.log(err))
});
After some brute force testing this combination worked.
exports.firestoreEmail = functions.firestore
.document( 'members/{memberId}' )
.onCreate( ( snap, context ) => {
const member = snap.data();
mail.setApiKey( SENDGRID_API_KEY );
const msg = {
to: member.email,
from: "hello#angularfirebase.com",
subject: "Welcome",
templateId: "xxx",
substitutions: {
name: member.name,
email: member.email,
membershipId: member.memberId
},
dynamic_template_data:
{
name: member.name,
email: member.email,
membershipId: member.memberId
}
};
return mail.send( msg ).then( () => console.log( 'email sent to receiver2!' ) )
.catch( err => console.log( err ) );
} );

what should I do If I want to do nothing in the one of my execution path in Background trigger cloud function?

as far as I know, background trigger cloud function should return a promise,right? but what if I want to do nothing in the one of my execution path ?
export const updateDataWhenUserUnattendTheEvent = functions.firestore
.document('events/{eventId}/Attendee/{userId}')
.onDelete((snap, context) => {
const eventID = context.params.eventId
const eventRef = snap.ref.firestore.collection('events').doc(eventID)
const db = admin.firestore()
return db.runTransaction(async t => {
const doc = await t.get(eventRef)
if (doc) {
const eventRankPoint = doc.data().rankPoint
let eventCapacity = doc.data().capacity
return t.update(eventRef,{
isFullCapacity : false,
capacity : eventCapacity + 1,
rankPoint: eventRankPoint - 1
})
} else {
// what should I write in here? empty promise?
return new Promise()
}
})
})
I want to my function worked only if the document is exist. so what should I do ? I write new Promise but .... I don't know what to do actually. thanks in advance
You can just return null if there's no asynchronous work to perform in some code path of your functions. You only truly need a promise if it tracks some async work.
Alternatively, you could return a promise that's resolved immediately with Promise.resolve(null)
Because db.runTransaction is an async function it will return a Promise all the time.
You can drop the else statement and the method will perform as expected because runTransaction will return Promise<void> which is a valid response for Cloud Functions
export const updateDataWhenUserUnattendTheEvent = functions.firestore
.document('events/{eventId}/Attendee/{userId}')
.onDelete((snap, context) => {
const eventID = context.params.eventId;
const eventRef = snap.ref.firestore.collection('events').doc(eventID);
const db = admin.firestore();
return db.runTransaction(async t => {
const doc = await t.get(eventRef);
if (doc) {
const eventRankPoint = doc.data().rankPoint;
let eventCapacity = doc.data().capacity ;
return t.update(eventRef,{
isFullCapacity : false,
capacity : eventCapacity + 1,
rankPoint: eventRankPoint - 1
});
}
});
});
You can also make the onDelete function async which means you can force it to always return a Promise - the below is valid and will exit the function correctly.
export const updateDataWhenUserUnattendTheEvent = functions.firestore
.document('events/{eventId}/Attendee/{userId}')
.onDelete(async (snap, context) => {
// Do Nothing
return;
});

I am receiving this error while getting notifications from firebase

'use strict'
const functions = require('firebase-functions');
const admin=require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification=functions.database.ref('/notifications/{user_id}/{notification_id }').onWrite((change,context) =>{
const user_id=context.params.user_id;
const notification_id=context.params.notification_id;
console.log('The user ID is :',user_id);
if(!change.after.val()){
return console.log('A notification has been deleted from database:',notification_id);
}
const fromUser=admin.database().ref(`/notifications/${user_id}/${notification_id}`).once('value');
return fromUser.then(fromUserResult=>{
const from_user_id=fromUserResult.val().from;
console.log('You have new notification from: : ', from_user_id);
const userQuery=admin.database().ref(`users/${from_user_id}/name`).once('value');
return userQuery.then(userResult=>{
const userName=userResult.val();
const deviceToken=admin.database().ref(`/users/${user_id}/device_token`).once('value');
return deviceToken.then(result =>{
const token_id=result.val();
const payload={
notification:{
title:"Friend Request",
body:`${userName} has sent you request`,
icon:"default"
}
};
return admin.messaging().sendToDevice(token_id, payload);
});
});
});
});
TypeError: Cannot read property 'from' of null
at fromUser.then.fromUserResult (/user_code/index.js:22:47)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
The only line of code where you're accessing a property called from is here:
const from_user_id=fromUserResult.val().from;
Therefore, fromUserResult.val() must be returning null.
fromUserResult is a DataSnapshot type object. According to the API documentation for the val() method, it can return null if there is no data at the location of the query. So, you will have to check for that case in your code.
I have achieved sending a notification with sender's name using this code:
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/Notifications/{receiver_user_id}/{notification_id}')
.onWrite((data, context) =>
{
const receiver_user_id = context.params.receiver_user_id;
const notification_id = context.params.notification_id;
if(!data.after.val())
{
console.log('A notification has been deleted :' , notification_id);
return null;
}
const sender_user_id = admin.database().ref(`/Notifications/${receiver_user_id}/${notification_id}`).once('value');
return sender_user_id.then(fromUserResult =>
{
const from_sender_user_id = fromUserResult.val().from;
const userQuery = admin.database().ref(`/Users/${from_sender_user_id}/name`).once('value');
return userQuery.then(userResult =>
{
const senderUserName = userResult.val();
console.log('You have notification from :' , senderUserName);
const DeviceToken = admin.database().ref(`/Users/${receiver_user_id}/device_token`).once('value');
console.log('Checkpoint2');
return DeviceToken.then(result =>
{
const token_id = result.val();
const payload =
{
notification:
{
//from_sender_user_id : from_sender_user_id,
title: "New Chat Request",
body: `${senderUserName} wants to connect with you`,
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id, payload).then(response =>
{
console.log('This was the notification Feature');
return null;
}).catch(error => {
console.error(error);
res.error(500);
});
});
});
});
});

Firebase cloud function with Firestore runTransaction call takes around 30 seconds to complete

This function initially makes a Stripe call to charge the user and then creates a transaction to update two different documents - related payment and user. I'm not sure how to optimize this code as I need transaction logic to update documents. How can I optimize this function?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const moment = require('moment')
admin.initializeApp(functions.config().firebase);
const stripe = require('stripe')(functions.config().stripe.testkey)
const db = admin.firestore();
exports.stripeCharge = functions.firestore
.document('users/{userId}/payments/{paymentId}')
.onWrite(event => {
const payment = event.data.data();
const userId = event.params.userId;
const paymentId = event.params.paymentId;
if (!payment || payment.charge) return;
const amount = payment.amount;
const duration = payment.duration;
const createdAt = payment.createdAt;
const idempotency_key = paymentId;
const source = payment.token.id;
const currency = 'usd';
const charge = {amount, currency, source};
return stripe.charges.create(charge, { idempotency_key })
.then(charge => {
if (!charge) return;
var userRef = db.collection('users').doc(userId);
var paymentsRef = userRef.collection('payments').doc(paymentId);
var transaction = db.runTransaction(t => {
return t.get(userRef)
.then(doc => {
let expiresAt;
if(doc.data().expiresAt
&& moment(doc.data().expiresAt).isAfter(createdAt)){
expiresAt = moment(doc.data().expiresAt).add(duration, 'M').toDate();
}else{
expiresAt = moment(createdAt).add(duration, 'M').toDate();
}
t.update(userRef, {
expiresAt: expiresAt,
timestamp: moment().toDate()
});
t.update(paymentsRef, { charge: charge });
});
})
.then(result => {
console.log('Successful');
})
})
.catch(err => { console.log(err) })
});
Returning the transaction itself solved the problem.
So instead of this:
var transaction = db.runTransaction(t => {
return t.get(userRef)
//...
Do this:
return db.runTransaction(t => {
return t.get(userRef)
//...

Resources