Unable to observe node (update not receiving) in firebase - firebase

I am creating a chat listing with react native and firebase. My firebase database is like this.
I am able to list the chats but it is not updating when a new chat adds or when I send a new message in old chat. My code is like this.
// find chat tread ids for a user.
firebase.database().ref('user/64/threads')
.on('value').then(snapshot => {
// find chat thread details for a id
const chatIds = snapshot.val();
for (let chatId of chatIds.keys()) {
firebase.database().ref('threads/'+chatId).once('value')
.then(snapshot1 => {
// find members from snapshot.val().members
// find id of other users.
if (chatId.split('-')[0] == '64') {
// find name of chatId.split('-')[1]
} else {
// find name of chatId.split('-')[0]
}
})
}
});
I am stuck in this forever. I am able to fetch chat listing one time but I am not getting whenever a new chat is added or when a new message is added in existing chat. Please help.

Related

send data to firebase with flutter

I am trying to send the data to firebase in my project which I was able to , yet I want the data to override the variable. The one I am using is adding at all the time
setState(() {
velocity = newVelocity;
if (velocity > highestVelocity) {
highestVelocity = velocity;
}
});
future= new Future.delayed(const Duration(seconds: 5));
_firestore.collection('collectionName').add({
'velocity' : velocity
});
}
I think there is update function to override the var. Can I someone help me with that?
To update an existing document, you must know the ID of that document. Once you do, you can update it with:
_firestore.collection('collectionName').doc("theIdOfYourDocument").set({
'velocity' : velocity
});
Also see: how can I set my document id as user uid in cloud fire store?

How to update the UI on firebase realtime database "push" in offline mode

I'm using react-native-firebase in my app. The problem i'm facing is how to handle the UI updates when user tries to push data when offline.
If the user is online we can use the on() method to get realtime updates but what to do when they are offline. We know that the pushed data is stored in the cache and pushed when user is online again. Can this cached data be used to do what i aim at achieving?
Here's the code i used to receive realtime updates:
var ref333 = firebase.database().ref(`/user-posts/${uid}/`)
ref333.on('value',function (snap) {
var s = snap.val();
console.log("NEW POSTS "+JSON.stringify(s))
})
The code i use to push the data.
var postData = {
uid: uid,
body: 'body',
title: 'title',
starCount: 0
};
// Get a key for a new Post.
var newPostKey = firebase.database().ref().child('posts').push().key;
var ref222 = firebase.database().ref(`/posts/${newPostKey}`)
var ref333 = firebase.database().ref(`/user-posts/${uid}/${newPostKey}`)
ref222.push(postData, function (onComplete) {
console.log("COMPLETED")
ref333.push(postData,function (onComplete) {
console.log("NEXT COMPLETED")
}, function (error) {
console.log("ERROR IN ",error)
})
}, function (error) {
console.log("error == "+error)
})
The .on snspashot listener should be triggered even if in offline mode.
According to the docs:
https://firebase.google.com/docs/database/web/read-and-write
You can use the value event to read a static snapshot of the contents
at a given path, as they existed at the time of the event. This method
is triggered once when the listener is attached and again every time
the data, including children, changes.
This should work in offline mode as well. If you are not receiving updates - something else is wrong.
This problem was solved by adding this lines of code to your native code:
https://rnfirebase.io/docs/v5.x.x/core/default-app#Enable-Database-Persistence

Facebook login in iOS (Swift 4) - Get permissions and store in Firebase

I've found some good resources on Stackoverflow and youtube helping getting around the fact that the Facebook iOS SDK descriptions are not up to date. I've now successfully managed to create the Facebook login feature and a new user is registered in Firebase. However my current issue is two fold.
1) I understand that Firebase do NOT store the email of the user under Authentication if the user log in with Facebook. My question is - how to get the email from Facebook so that I can store it under the users profile, and how do I ensure that a user that has signed in / logged in with Facebook one day and by email another day are the same user?
2a) The .userFriends info is a list of friends that also use the app - I'm struggling to understand what info that Facebook provide and how I can use this to suggest other friends the user can follow in the app.
I've read the Facebook SDK info! But can someone help translating this into what it means in terms of Swift 4...
2B) Not knowing the data structure - I'm thinking of storing .userFriends into a new node - but unsure if I should do it under the specific user profile, or denormalise it and put it under root with the user uid as the identifier... let me know your thoughts please..
Working code - issue is with the commented section
#objc func loginButtonClicked() {
let loginManager = LoginManager()
loginManager.logIn(readPermissions: [.publicProfile, .email, .userFriends], viewController: self) { loginResult in // request access to user's facebook details
switch loginResult {
case .failed(let error):
print(error)
case .cancelled:
print("User cancelled login.")
case .success(let grantedPermissions, let declinedPermissions, let accessToken):
print(grantedPermissions)
print(declinedPermissions)
// Check permissions granted and declined add do action depending... eg. get name and surname for profile
// if FacebookAccessToken.grantedPermissions = {
// // TODO: publish content.
// }
// else {
// var loginManager = LoginManager()
// loginManager.logIn(readPermissions: [.publicProfile], viewController: self) { loginResult in
// //TODO: process error or result.
// }
// }
FacebookAccessToken = accessToken
let credential = FacebookAuthProvider.credential(withAccessToken: (FacebookAccessToken?.authenticationToken)!)
Auth.auth().signIn(with: credential) {( user, error) in
if let error = error {
print(error)
return
}
let currentUser = Auth.auth().currentUser
// Navigates back
self.dismiss(animated: true, completion: {});
self.navigationController?.popViewController(animated: true);
print("Successfully logged in user with Facebook")
}
}
}
}

Firebase: retriving friend's data (Ionic Framework)

I have an app where I need to fetch the user's friends geolocation data. What I need to do is:
1) loop the current user's node under "friends" node to get all of the user's friends
2) with that data, go loop "users/[[friend uid]]" for each friend and pull the lat and long from geolocation along with the friend's display name
This should be a subscribed event, as in if the geolocation updates in the server it should also show it in the app/update the variables.
Friends node structure is like this:
friends
current user UID
random id (not needed)
friend 1 UID (needed)
random id (not needed)
friend 2 UID (needed)
etc
Here's also a pic of the whole database structure:
Thank you!
Edit: here is the current code for retrieving friends, how could I implement getting the geolocation of each friend retrived?
friendsNode = firebase.database().ref('/friends');
....
getFriendsList() {
let friendsUID = [];
this.friendsNode.child(firebase.auth().currentUser.uid).on('value', (snapshot) => {
let allFriends = snapshot.val();
this.myFriends = [];
for (var i in allFriends)
friendsUID.push(allFriends[i].uid);
this.userService.getallusers().then((users) => {
this.myFriends = [];
for (var j in friendsUID)
for (var key in users) {
if (friendsUID[j] === users[key].uid) {
this.myFriends.push(users[key]);
}
}
this.events.publish('friends');
}).catch((err) => {
alert(err);
})
})
}

How to bulk delete Firebase anonymous users

Due to my probable misuse of anonymous authentication (see How to prevent Firebase anonymous user token from expiring) I have a lot of anonymous users in my app that I don't actually want.
I can't see any way to bulk delete these users. Do I have to do it manually one-by-one? Is there anyway to use the API to access user accounts and manipulate them for users other than the current user?
This code sample uses the Firebase Admin SDK for Node.js, and will delete any user that has no providerData, which means the user is anonymous:
function deleteAnonymousUsers(nextPageToken) {
adminApp
.auth()
.listUsers(20, nextPageToken)
.then(function(listUsersResult) {
listUsersResult.users.forEach(function(userRecord) {
if (userRecord.providerData.length === 0) { //this user is anonymous
console.log(userRecord); // do your delete here
adminApp.auth().deleteUser(userRecord.uid)
.then(function() {
console.log("Successfully deleted user");
})
.catch(function(error) {
console.log("Error deleting user:", error);
});
}
});
if (listUsersResult.pageToken) {
// List next batch of users.
deleteAnonymousUsers(listUsersResult.pageToken);
}
})
.catch(function(error) {
console.log('Error listing users:', error);
});
}
There is no way in the Firebase Console to bulk-delete users.
There is no API to bulk-delete users.
But there is administrative API that allows you to delete user accounts. See https://firebase.google.com/docs/auth/admin/manage-users#delete_a_user
I just wanted to add a method I just used to (sort-of) bulk-delete. Mostly because I felt clever after doing it and I am not that clever.
I downloaded a mouse-automation application that lets you record your mouse clicks then replay it automatically. I just deleted almost 1000 users while playing the piano lol.
I used Macro Recorder and it worked like a charm. Just recorded a few iterations in the console of me deleting users, set it to repeat 500 times and walked away.
I know this isn't a very technical answer, but it saved me hours of monotonous mouse clicking so hopefully someone else looking for a way to bulk-delete will benefit from it as well. I hated the fact that there was no bulk-delete and really needed a way out of it. It only took about 20 manual deletes to realize there were apps that could do what I was doing.
If you do not need to do it on a large scale and you want to delete some anonymous users from Firebase Console UI, but you are lazy to click on 250 users one-by-one, run the following code in your console (screen where table with users is shown):
rows = Array.from(document.querySelectorAll('td.auth-user-identifier-cell')).map(td => td.parentNode).filter((tr) => tr.innerText.includes('anonymous'))
var nextTick = null
function openContextMenu(tr) {
console.log('openning menu')
tr.querySelector('.edit-account-button').click()
nextTick = deleteUser
}
function deleteUser() {
console.log('deleting user')
document.querySelector('.cdk-overlay-connected-position-bounding-box button:last-of-type').click()
nextTick = confirmDelete
}
function confirmDelete() {
console.log('confirming action')
document.querySelector('.cdk-global-overlay-wrapper .confirm-button').click()
nextTick = getUser
}
function getUser() {
console.log('getting user')
openContextMenu(rows.shift())
}
nextTick = getUser
step = 500
setInterval(() => {
nextTick()
}, step)
It basically selects all rows which contain anonymous user and simulate you clicking the three dots, then clicking on delete account and as a last step it confirms action in the modal which appears.
Before running the script, select 250 rows per page in the table's footer. When all anonymous users are removed, you must manually go to next page and re run the script (or code in another "tick" which paginates for you).
It takes 1.5 second to delete one user (you can modify this with step variable, but I do not recommend go lower than 500ms - mind the UI animations).
It runs also in a tab in background so you can watch some YT in meantime :)
Update 2021:
I had around 10,000 anonymous users, and #regretoverflow's solution lead to exceeding the delete user quota. However, slightly tweaking the code to utilize the admin's deleteUsers([userId1, userId2, ...]) API works like a charm.
function deleteAnonymousUsers(nextPageToken: string | undefined) {
firebaseAdmin
.auth()
.listUsers(1000, nextPageToken)
.then(function (listUsersResult) {
const anonymousUsers: string[] = [];
listUsersResult.users.forEach(function (userRecord) {
if (userRecord.providerData.length === 0) {
anonymousUsers.push(userRecord.uid);
}
});
firebaseAdmin
.auth()
.deleteUsers(anonymousUsers)
.then(function () {
if (listUsersResult.pageToken) {
// List next batch of users.
deleteAnonymousUsers(listUsersResult.pageToken);
}
})
})
}
deleteAnonymousUsers(undefined);
There is a firebase-functions-helper package, that can help to delete firebase users in bulk.
// Get all users
firebaseHelper.firebase
.getAllUsers(100)
.then(users => {
users.map(user => {
firebaseHelper.firebase
.deleteUsers([user.uid]);
})
})
The code above will get 100 users, and delete all of them. If you don't pass the number, the default value is 1000. You can read the instruction on Github repository.
I faced the same problem today then I found Firebase Admin SDK. I am using Node.js which is very easy to install, so you can try the following code. It is not a complete answer I know but one can build its own script/application to delete stored uids. Yet, there is no way to retrieve a list, so you have to build one somehow every time you create an anonymous account.
First, download your 'serviceAccountKey.json' which can be done through the Firebase Console (Project Settings). In my case I renamed the download file to a more friendly name and saved to documents folder.
console.firebase.google.com/project/yourprojectname/settings/serviceaccounts/adminsdk
Useful links:
Firebase Admin SDK Setup
Firebase Admin User Management
Firebase Admin Database API
Then, play around using Windows cmd.exe or any other shell. The 'npm install -g' installs firebase-admin globally in your machine.
$ npm install firebase-admin -g
$ node
> var admin = require("firebase-admin");
> admin.initializeApp({
credential: admin.credential.cert("./documents/yourprojectname-firebase-admin.json"),
databaseURL: "https://yourprojectname.firebaseio.com"
});
> var db = admin.database();
// Of course use an existent UID of your choice
> admin.auth().getUser('2w8XEVe7qZaFn2ywc5MnlPdHN90s').then((user) => console.log
(user))
> admin.auth().deleteUser('2w8XEVe7qZaFn2ywc5MnlPdHN90s').then(function() {
console.log("Successfully deleted user");
}).catch(function(error) {
console.log("Error deleting user:", error);
});
// To get access to some key/values in your Database:
> var ref = db.ref("users/1234");
> ref.once("value", function(snapshot) {
console.log(snapshot.val());
});
I was writing myself a firebase functions function with Firebase auth.
It works like a charm for me and i can clean with one API call.
// Delete all Anon User
exports.deleteUser = functions.https.onRequest(async (req, res) => {
const admin = require("firebase-admin");
//initialize auth
admin.initializeApp();
//create auth instance
const auth = admin.auth();
//Get the list of all Users
const allUsers = await auth.listUsers();
//Identify the Anon User give other user null
const allUsersUID = allUsers.users.map((user) => (user.providerData.length === 0) ? user.uid : null);
//remove the null
const filteredallUsersUID = allUsersUID.filter(e => e !== null)
//delete and answer the API call
return auth.deleteUsers(filteredallUsersUID).then(() => res.send("All Anon-User deleted"));
});
With this you can just simply call your API URL
https://[Your_API_URL]/deleteUser
Just require basic knowledge of Firebase Functions.
I assume this could be also added to a cron job.
I had the same problem. because Firebase doesn't provide any API to delete bulk users but this is how I have deleted all anonymous users.
Download all the users as json via firebase tool
firebase auth:export users --format=json
https://firebase.google.com/docs/cli/auth#file_format
You can write a firebase cloud function to trigger or write a action method to trigger
import the json file in to your file,
const Users = require('./users.json'); // ES5 <br>
import Users from './users.json'); // ES6 <br>
normally anonymous user doesn't have email so it is easy to delete the record which doesn't have email id
Users.users.map(user => {
setTimeout(() => {
admin.auth().deleteUser(user.localId).then(() =>{
console.log("Successfully deleted user");
})
.catch((error) => {
console.log("Error deleting user:", error);
});
}, 20000);
});
Don't try to reduce the timeout second. It will throw below error
Error deleting user: { Error: www.googleapis.com network timeout. Please try again.
The Firebase Admin SDK can also delete multiple users at once.
Here is Node.js sample.
admin.auth().deleteUsers([uid1, uid2, uid3])
.then(deleteUsersResult => {
console.log('Successfully deleted ' + deleteUsersResult.successCount + ' users');
console.log('Failed to delete ' + deleteUsersResult.failureCount + ' users');
deleteUsersResult.errors.forEach(err => {
console.log(err.error.toJSON());
});
})
.catch(error => {
console.log('Error deleting users:', error);
});
Notice: there is a limitation as list all users.
The maximum number of users allowed to be deleted is 1000 per batch.

Resources