I have firebase user id, but I can't access name - firebase

So I'm making a chat app, and I need to access the user's name. But I only have the users ID. Is there any way I can search through the entire database and find a user with the same id as I have?
Firebase Tree Setup Image
this is my firebase tree setup. So I have the users id: eg. 1JIalS7s85PgucxZgGi48ao9Oaf2
However, I don't have the user's name: eg. DummyBoy
Is there a way to find the name

You can store the names of your users like this.
{
"users": {
"{uid}": {
"name": "John"
}
}
}
Now using a user's uid, you can get their name in swift like this:
let ref = FIRDatabase.database().referenceWithPath("users/\(uid)/name")
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
if let name = snapshot.value as? String {
print(name)
}
})

Related

Update Firebase Realtime Data Base Specific Value in an Object

I am learning Flutter with Firebase. I have some dummy data in Firebase Realtime Data base as:
{
"postsnode": {
"posts": [
{
"postId": "u1",
"postName": "p1"
}
]
},
"usersnode": {
"users": [
{
"userId": "u1",
"userName": "bla bla 1"
},
{
"userId": "u2",
"userName": "bla bla 2"
}
]
}
}
The screen shot of the console database structure is:
I have successfully performed a query on my usersnode object to get the specific users:
void queryDB(BuildContext context) async {
AppUtil.showLoader(context: context);
FirebaseDatabase.instance.ref().child('usersnode/users').orderByChild('userId').equalTo("u1").get().then((snapshot) {
if (snapshot.exists) {
print("user:::" + snapshot.value.toString());
final jsonResponse = json.encode(snapshot.value);
List<dynamic> list = json.decode(jsonResponse);
List<Users> users = [];
list.forEach((element) {
Users usersModel = Users.fromJson(element);
users.add(usersModel);
});
users.forEach((element) {
debugPrint("UseX:::" + element.userName);
});
} else {
print('No data available.1');
}
AppUtil.dismissLoader(context: context);
// }).onError((error, stackTrace) {
// print('No data available.2');
// AppUtil.dismissLoader(context: context);
});
}
I just want to update my specific object suppose the users object with the userId=u1 only!
Can somebody help me getting this, update using the query! or I'm doing the wrong way!
Actually I just simple want to update the object based on some condition:
Update Users -> where userId=u1
Thanks in Advance!
Welcome to Flutter Firebase!
First, you should probably change your data structure. There's no need to have a random incremental ID for users. You can use their unique ID as the key for the object:
{
"posts": {}
...
"users": {
"u1": {
"userName": "bla bla 1"
},
"u2": {
"userName": "bla bla 2"
}
}
}
Then, you can do this:
final String userId = 'u1';
final userDoc = FirebaseDatabase.instance.reference().child('users/$userId');
If you're planning on storing a lot of data in posts or users, I highly recommend that you check Cloud Firestore. It offers better structure and more advanced data types.
You're starting with a very flimsy foundation to your database if you go down the route you're taking. A proper schema would look like this:
{
"posts": {
"$postID": {
"postName": "Some Name"
// ...
}
}
"users": {
"$userID": {
"userName": "Some Username"
}
}
}
You would be wise to avoid arrays entirely when using firebase database. This isn't a firebase standard, it's a NoSQL practice.
In short, NoSQL databases use key value pairs to structure data. Since you won't have any two users with the same ids, nor two posts with the same ids, using key-value pairs in your database let you easily accomplish what you're trying to do by design.
I just want to update my specific object suppose the users object with
the userId=u1 only! Can somebody help me getting this, update using
the query! or I'm doing the wrong way!
The way to do this in the user nodes is as simple as this:
String userID = "$userID"; // where $userID is your targeted user
String newUserName = "$newUsername"; // this is the new data you're trying to change
DatabaseReference userRef = FirebaseDatabase.instance.ref().child('users').child(userID);
userRef.update({
"userName": newUserName,
"timestamp": ServerValue.timestamp,
});
I have successfully performed a query on my usersnode object to get the specific users:
Obviously your old implementation won't work when you update your schema to be key-value paired. But that's a good thing because now you can do proper queries which you can then convert into arrays in the app. You would effectively parse through the DatabaseSnapshot value, which is a Map where the keys are the userIDS and the values are corresponding data.
The way you would load the users into your app with is as follows:
DatabaseReference usersRef = FirebaseDatabase.instance.ref().child('users');
usersRef.orderByChild("userName").once(DatabaseEventType.value).then((DatabaseEvent databaseEvent) {
// (You should update to the latest package which has breaking changes like this you need to adjust to)
// First get the snapshot from the new DatabaseEvent object
DataSnapshot snapshot = databaseEvent.snapshot;
// Convert the value into a map you can parse through
Object? snapshotValue = snapshot.value;
Map<dynamic, dynamic> valueMap = snapshotValue is Map<dynamic, dynamic> ? snapshotValue : {};
// Print the results for debugging
if(valueMap.isEmpty) {
debugPrint("No users found");
} else {
debugPrint("${valueMap.length} user${valueMap.length == 1 ? '' : 's'} found");
}
// Loop through the keys of this map (which are the userIDS)
List<Users> users = [];
for(String userID in valueMap.keys) {
Users userModel = Users.fromJson(valueMap[userID]);
users.add(usersModel);
debugPrint("UseX:::" + userModel.userName);
}
AppUtil.dismissLoader(context: context);
});
Lastly, if you allow users to create posts, you might want to consider adding the following node to your schema in addition to just "posts":
"user_posts" {
"$userID": {
"$postID": POST_OBJECT,
// ...
}
}
Then when you want to load the posts created by the user, rather than only being able to query the "posts" node for posts created by the user (which you'll have a limited querying ability), you query the posts under this specific user's posts (by timestamp for example).
If you do it this way, you'd store a copy of the same object under the user's posts node and posts' node.
You seem new to firebase and have a limited understanding of how the database works. It can get very messy very fast and the most important thing to do is understand how you're going to use the data, how it's going to be queried, and most importantly, how you want to be able to sort it (by alphabetical order, by ranking, by number of likes, by date created, etc.).
Understanding these concepts now is very important because it's directly tied to your database security rules as well (which you wouldn't be able to protect with the way you were doing it before).
My advice would be to look up a quick start guide on NoSQL databases (maybe just the firebase documentation starting guide), look at the firebase database security rules guide, understand what fanning out data is, and then start looking into cloud functions so you can do useful things when data is created, updated, or deleted.
It's very easy to neglect this stuff early on while only focusing only on the app, but this is equally important despite not being something your end user would spend a second thinking about. Without a solid database, you'll run into endless issues in the future.
Good luck :)

Flutter-Firebase RTDB : Is Push ID mandatory for reading data from Firebase Realtime database?

My current experiment:
I want user to sign in and enter details
When next time he signs in, i want to retrieve his saved information
My intended database structure:
-"users
------"uid"
-----------firstName
-----------lastName`
I use the below code in flutter to create records:
await FirebaseAuth.instance.signInWithEmailAndPassword( email: email, password:
password).then((value)
{
if(value.user.uid != null )
{
final dbRef = FirebaseDatabase.instance.reference().child('users');
dbRef.push().child(user.uid.toString()).set(User().toJson());
}
}
the data gets created with a push key/ID inbetween:
-users
------MFvvXpeRmoQvXkd5VS8 `<---Push ID generated by Firebase`
--------------k8IL4xLQKRf82dxlXNLSHEt2
-----------------------firstName: "sadsadda"
------------------------lastName: "asdsadsad"`
Based on documentations, When i try to retrieve the data using the following code:
final dbRef = FirebaseDatabase.instance.reference().child('users').child(user.uid.toString());
dbRef.equalTo(user.uid.toString()).once().then((snapshot)
{
/*snapshot has value null
}
);
//I even added listener<br>
dbRef.onChildAdded.listen((event) {
readUserInfo(event.snapshot); // even here snapshot value is null.
});
Just for testing purpose, i tried to pass the push key in-between by hardcoding,
final dbRef = FirebaseDatabase.instance.reference().child('users').child('-
MFvvXpeRmoQvXkd5VS8').child(user.uid.toString());`
then "onChildAdded" listener was able to pickup the child entries.
Is this the expected behaviour ? or is there a way to avoid this randomly generated push id?
Thanks for your time in advance
To write the user data under their UID, don't call push(), but simply do:
dbRef.child(user.uid.toString()).set(User().toJson());
To then read the data for the user back, use:
final dbRef = FirebaseDatabase.instance.reference().child('users').child(user.uid.toString());
dbRef.onValue.listen((event) {
readUserInfo(event.snapshot);
});
The .childAdded is needed when you want to read a list of child nodes, for example to read all users:
final dbRef = FirebaseDatabase.instance.reference().child('users');
dbRef.onChildAdded.listen((event) {
readUserInfo(event.snapshot);
});

Firebase get value from database

The question is: How to take the uid row when you only know the user his username? for example, you only know 'senneken' and you want to know the uid of 'senneken'
Extra information:
My user database looks like this
I want to add friends to users. I can check if the user exists for them by doing
searchButton.addEventListener('click', function (event) {
event.preventDefault();
username = searchUsername.value;
var ref = firebase.database().ref('users').orderByChild("username").equalTo(username).once("value", snapshot => {
const userData = snapshot.val();
if (userData) {
console.log("Username " + username + " was found");
} else {
console.log("No user found");
}
But now I want to add the users UID in my database
And I can add the friends username by doing
addFriendButton.addEventListener('click', function (event) {
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
var ref = firebase.database().ref("users").child(user.uid).child("friends").push({
username: username
})
}
});
});
Because I use push there is always a random ID generated under friends but I would like to take the UID from the user that I want to add and put that under my friends (instead of the random UID)
In this case the collection of friends seems like a set: each specific UID can either be in there, or it cannot be in there. It cannot be in there more than once, and order seems to not matter. The solution is to not use a push ID, but model it as a set like this:
friends
uid1
uid2: true
uid3: true
This way you can simply set a user as a friend with:
firebase.database().ref("friends").child(user.uid).child(username).set(true)
You might notice that I also turned the collections of friends into a top-level collection. Nesting information about friends under other profile information about a user is an anti-pattern, which makes it hard to secure data, leads to downloading more data than is needed, and in general is not recommended by Firebase experts.

Firebase - How to permanently save user profile?

Firebase Console only allows to set email address and password, there is no option to save user's profile but this can be done using code:
user.updateProfile({
displayName: "Chinmay Sarupria"
}).then(function() {
console.log(user.displayName);
}, function(error) {
console.log(error);
});
If this is the way to save user data permanently then it is impossible to write code for every user just to save their displayName like this or is doing via code permanent, at the moment it is working for me but I'm not sure if it will remain like that forever.
Ofcourse, I could save the user data in realtime database and then fetch it based on user's uid but if saving user data in the user variable is possible then that is much better than getting the data from database.
After you reference your user object you can update values under the UID for that user.
var rootRef = new Firebase('https://yourapp.firebaseio.com');
// Check the current user login status and redirect if not logged in
var user = rootRef.getAuth();
if (user) {
var user = rootRef.getAuth();
var userRef = rootRef.child('users').child(user.uid);
... do something with the logged in user...
}
function writeData () {
var user = rootRef.getAuth();
var userRef = rootRef.child('users').child(user.uid);
var profileRef=userRef.child('profile').push();
profileRef.update ({
name: "Tony",
position: "Developer"
});
};
This should give your user profile a structure something like this:
}
"users" : {
"067f75bf-4a07-473e-82e5-d9a5ee11be17" : {
"profile" : {
"-KN2dG5X4lLpp0fwfsXK" : {
"name" : "Tony",
"position" : "Developer"
}
}
}
}
Note the push() function gives you the randomly generated key. You may not need it.
Hope this helps.

Firebase / AngularFire create user information

I'm creating a new user with AngularFire. But when I sign the user up I also ask for first name and last name and I add that info after registration.
$firebaseSimpleLogin(fbRef).$createUser($scope.signupData.email, $scope.signupData.password).then(function (user) {
// Add additional information for current user
$firebase(fbRef.child('users').child(user.id).child("name")).$set({
first: $scope.signupData.first_name,
last: $scope.signupData.last_name
}).then(function () {
$rootScope.user = user;
});
});
The above code works, it creates node fin Firebase (users/user.id/ ...).
The problem
When I login with the new user I get the user default information: id, email, uid, etc. but no name. How can I associate that data automatically to the user?
You can't. Firebase hides the complexity of login management by storing the login details in its own datastore. This process knows nothing of your app's forge, which means it doesn't know if or where you're storing any additional user information. It returns the data that it does know about as a convenience (id, uid, email, md5_hash, provider, firebaseAuthToken).
It's up to your app to then take the [u]id and grab whatever app specific user information you need (such as first name, last name). For an Angular app, you'd want to have a UserProfile service which retrieves the data you're looking for once you get the authentication success broadcast.
Also, in your snippet, consider changing
.child(user.id)
to
.child(user.uid)
This will come in handy if you ever support Facebook/Twitter/Persona authentication later on. uid looks like "simplelogin:1" - it helps to avoid unlikely but possible id clashes across providers.
I have the same issue on this and feel like noone actually has a clear answer (2 years on). But here is the rough structure of how such a service could look like:
app.factory('Auth', function(FURL, $firebaseAuth, $firebaseObject, $rootScope, $window){
​
var ref = new Firebase(FURL);
var auth = $firebaseAuth(ref);
​
var Auth = {
user: {},
​
login: function(user){
return auth.$authWithPassword({
email: user.email,
password: user.password
});
},
​
signedIn: function(){
return !!Auth.user.provider;
},
​
logout: function(){
return auth.$unauth;
}
};
​
// When user auths, store auth data in the user object
auth.$onAuth(function(authData){
if(authData){
angular.copy(authData, Auth.user);
// Set the profile
Auth.user.profile = $firebaseObject(ref.child('profile').child(authData.uid));
Auth.user.profile.$loaded().then(function(profile){
$window.localStorage['gym-key'] = profile.gym.toString();
});
} else {
if(Auth.user && Auth.user.profile){
Auth.user.profile.$destroy();
}
​
}
});
​
return Auth;
});

Resources