I am using google cloud functions to register push notifications through firebase. In my app, i have a notifications reference that changes for a current user whenever they get a new follower or like, etc. As of right now I am able to send the notification to the phone whenever that whole reference child changes
For example, if any single post is liked, then it will send a notification. What I need to do is observe the current user to only send the notification that single person.
Here is my JavaScript file
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendPushNotification = functions.database.ref('/notification/{id}').onWrite(event => {
const payload = {
notification: {
title: 'New message arrived',
body: 'come check it',
badge: '1',
sound: 'default',
}
};
return admin.database().ref('fcmToken').once('value').then(allToken => {
if (allToken.val()) {
const token = Object.keys(allToken.val());
return admin.messaging().sendToDevice(token, payload).then(response => {
});
}
});
});
I would like to replace this line:
functions.database.ref('/notification/{id}').onWrite(event => {
With this:
functions.database.ref('/notification/{id}').(The current user ID).onWrite(event => {
How do I get the current users id?
You seem very new to JavaScript (calling it JSON is sort-of a give-away for that). Cloud Functions for Firebase is not the best way to learn JavaScript. I recommend first reading the Firebase documentation for Web developers and/or taking the Firebase codelab for Web developer. They cover many basic JavaScript, Web and Firebase interactions. After those you'll be much better equipped to write code for Cloud Functions too.
Now back to your question: there is no concept of a "current user" in Cloud Functions. Your JavaScript code runs on a server, and all users can trigger the code by writing to the database.
You can figure out what user triggered the function, but that too isn't what you want here. The user who triggered the notification is not the one who needs to receive the message. What you want instead is to read the user who is the target of the notification.
One way to do this is to read it from the database path that triggered the function. If you keep the notifications per user in the database like this:
user_notifications
$uid
notification1: ...
notification2: ...
You can trigger the Cloud Function like this:
exports.sendPushNotification = functions.database.ref('/user_notification/{uid}/{id}').onWrite(event => {
And then in the code of that function, get the UID of the user with:
var uid = event.params.uid;
For Swift 3.0 - 4.0
You can do this:
import Firebase
import FirebaseAuth
class YourClass {
let user = Auth.auth().currentUser
let userID = user.uid
// user userID anywhere
}
Related
This question already has an answer here:
How to get FirebaseUser from a uid?
(1 answer)
Closed 8 months ago.
New to vue/firebase. I was able to lookup how to pull up “current user” data from auth no problem but trying to write a js composable that I can pass in any user id (not necessarily current user) and it will return the user object or at least displayName.
All the docs/vids I can find on the topic reference getting info on *current user *only not another user. From the Google Docs it says I should be able to do this in the "Retrieve user data" section. Closest model to Vue code-wise seems to be “Node.Js” but it isn't working.
Here's what I've got in getUserById
import { getAuth } from 'firebase/auth'
const getUserById = (u) => { // u = user id
const userData = null
getAuth()
.getUser(u)
.then((userRecord) => {
// See the UserRecord reference doc for the contents of userRecord.
console.log(`Successfully fetched user data: ${userRecord.toJSON()}`);
userData = userRecord
})
.catch((error) => {
console.log('Error fetching user data:', error);
});
return { userData }
}
export default getUserById
The error I get is getUser is not a function. I tried adding getUser to the import but same error.
There is no way to look up information about just any user by their UID in the client-side APIs of Firebase as that would be a security risk. There is an API to look up a user by their UID in the Admin SDK, but that can only be used on a trusted environment (such as your development machine, a server you control, or Cloud Functions/Cloud Run), and not in client-side code.
If you need such functionality in your app, you can either wrap the functionality from the Admin SDK in a custom endpoint that you then secure, or have each user write information to a cloud database (such as Realtime Database or Firestore) and read it from there.
Also see:
How to get FirebaseUser from a uid?
Firebase get user by ID
Is there any way to get Firebase Auth User UID?
My database is structured as follows Collection("Message").Document("message")
But in reality, I want any change in the database's main collection to be monitored—when a document is added. I added the message document because I thought that maybe the function wasn't being called since my documents are the auto-generated ones. However, the problem persists...
Just for background I am an iOS developer, so perhaps I am doing something wrong here:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendPushNotifications = functions.database.ref('/Messages/{message}').onCreate((snapshot,context) => {
console.log(snapshot);
console.log(context);
var topic = "/topics/sentMessages";
var payload = {
data: {
message : 'You recieved a new message!'
}
}
return admin.messaging().sendToTopic(topic,payload).then((response) => {
return response;
})
})
For additional background: The application receives push notifications fine when using the console whether it be directly to the testing device or using topics. This problem is strictly when writing to firebase Firestore...
When you said "Collection("Message").Document("message")" that suggested to me that you're using Firestore as your database. However, your function is targeting changes to Realtime Database, which is a completely different thing. functions.database builds function for Realtime Database. functions.firestore builds functions for Firestore. You will want to read the documentation on Firetore triggers to learn how to write them.
I have written a Firebase cloud function in which I want to get every users internal collection called 'numbers' and read each document out of that collection to do some comparisons.
Any idea how to do this?
I am pretty new to firebase and for some reason the database navigation commands are just not sticking with me very well.
I have tried a handful of commands with no success
const snapshot = functions.database.collection('users').collection('numbers').get()
let sfRef = db.collection('users');
sfRef.getCollections().then(collections => {
collections.forEach(collection => {
console.log('Found subcollection with id:', collection.id);
});
});
Here is a loose cloud code infastructure
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
export const prize1 = functions.pubsub.schedule('every 5 minutes').onRun((context) => {
const users = functions.database.ref('/users/numbers')
console.log("")
return null;
});
I feel like I have a good idea of how to do it, but the syntax is holding me back.
The collection of users. Go through each document in here, i.e. each user.
In each user go to the collection called numbers.
In the collection called numbers go through each document and find the numbers field to do logic/comparisons with.
Hopefully this can help you understand the way my database is ordered.
You could try it like this:
let usersRef = db.collection('users');
let allUsers = usersRef.get();
.then(userSnapshot => {
userSnapshot.forEach(userDoc => {
userDoc.ref.collection('numbers').get().then(numSnapshot => {
numSnapshot.forEach(numDoc => {
console.log(numDoc.data().numbers);
// here you got your numbers document with the numbers field
});
});
});
})
.catch((error) => {
console.log("Error getting document: ", error);
});
For more information you can look here and here.
You can't use functions for accessing the database. What you've defined as functions is for building triggers that respond to events. If you want to get data from Cloud Firestore, you should be using the Firebase Admin SDK via your admin instead. It might also help if you look through the official samples.
I will also point out that your code samples appear to be split between accessing Cloud Firestore and Realtime Database, which are different database products. Your screenshot shows Firestore, so ignore any APIs for Realtime Database.
The database structure looks like this
-LGw89Lx5CA9mOe1fSRQ {
uid: "FzobH6xDhHhtjbfqxlHR5nTobL62"
image: "https://pbs.twimg.com/profile_images/8950378298..."
location: "Lorem ipsum, lorem ipsum"
name: "Lorem ipsum"
provider: "twitter.com"
}
How can I delete everything, including the -LGw89Lx5CA9mOe1fSRQ key programmatically?
I looked at this, but it's outdated and deprecated Firebase: removeUser() but need to remove data stored under that uid
I've also looked at this, but this requires for user to constantly sign in (I'm saving the user ID in localStorage) and it returns null on refresh if I write firebase.auth().currentUser. Data records and user accounts are created through social network providers and I can see the data both on Authentication and Database tab in the Firebase console.
I've tried with these piece of code but it does nothing.
// currentUser has a value of UID from Firebase
// The value is stored in localStorage
databaseChild.child(currentUser).remove()
.then(res => {
// res returns 'undefined'
console.log('Deleted', res);
})
.catch(err => console.error(err));
The bottom line is, I need to delete the user (with a specific UID) from the Authentication tab and from the Database at the same time with one click.
I know that there is a Firebase Admin SDK but I'm creating a Single Page Application and I don't have any back end code. Everything is being done on the front end.
Any kind of help is appreciated.
With suggestions from #jeremyw and #peter-haddad I was able to get exactly what I want. Here is the code that is hosted on Firebase Cloud Functions
const functions = require('firebase-functions'),
admin = require('firebase-admin');
admin.initializeApp();
exports.deleteUser = functions.https.onRequest((request, response) => {
const data = JSON.parse(request.body),
user = data.uid;
// Delete user record from Authentication
admin.auth().deleteUser(user)
.then(() => {
console.log('User Authentication record deleted');
return;
})
.catch(() => console.error('Error while trying to delete the user', err));
// Delete user record from Real Time Database
admin.database().ref().child('people').orderByChild('uid').equalTo(user).once('value', snap => {
let userData = snap.val();
for (let key of Object.keys(userData)) {
admin.database().ref().child('people').child(key).remove();
}
});
response.send(200);
});
Also, if you are facing CORS errors, add the mode: 'no-cors' option to your fetch() function and it will work without any problems.
The link you already found for deleting the user-login-account client-side is your only option if you want to keep the action on the client. Usually you want to keep most of the actions for things like account creation/deletion on the server for security reasons, and Firebase forces the issue. You can only delete your account if you were recently logged in, you can't have client-side start deleting old/random accounts.
The better option is to create your own Cloud Function to handle everything related to deleting a user. You would have to use the Admin SDK that you already found for this... but you could have that Cloud Function perform as many actions as you want - it will have to delete the user from the Auth tab, and delete the matching data in the Database.
Just trying to understand the process for sending a Firebase Cloud Message using Cloud Functions to notify all users who have my app installed on their phone. This would fire whenever a new event has been added at a particular branch, as follows:
var functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const payload = {
notification: {
title: 'New event added'
}
};
exports.bookingsChanged = functions.database.ref("/Events")
.onWrite(event => {
return admin.messaging().sendToDeviceGroup("latest_events", payload);
});
The above function I've uploaded doesn't appear to send the message to the Android device I'm using at all, despite setting up and testing FCM using the Firebase Console option to send messages. I've noticed there is little documentation for this at the moment, so any help would be greatly appreciated!
EDIT
I may've missed this, but I've replaced the string 'latest_events' with my Android application package name that I assume is required, as per the console to target a 'User Segment'.
Ended up solving this by waiting for a topic I had set up to appear in the Firebase Notifications dashboard. I then changed the following code to send to this topic directly:
return admin.messaging().sendToTopic("latest_events", payload);
I also found out that you have to provide a token when using 'sendToDevicegroup' after coming across the API documentation. Therefore, topics are more effective in my use case as I do not wish to obtain tokens to send to specific user devices.
Hope this helps someone who experiences a similar problem!
ADDITIONAL EDIT
If like me, you would like to alert users only of new events that have been added to a specific branch, typically including a push id, I've created the following code to implement this.
With a little help from the examples in the documentation, this will evaluate the number of records at the location compared to the previous location. Thus, this will only alert users of new child records that are added, rather than every time a record is edited and deleted.
var functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.bookingsChanged = functions.database.ref("/Bookings").onWrite(event
=> {
var payload = {
notification: {
title: "A new event has been added!"
}
};
if (event.data.previous.exists()) {
if (event.data.previous.numChildren() < event.data.numChildren()) {
return admin.messaging().sendToTopic("latest_events", payload);
} else {
return;
}
}
if (!event.data.exists()) {
return;
}
return admin.messaging().sendToTopic("latest_events", payload);
});