I been trying to use Firebase to set up a simple DB to store usernames.
Right now am running a localhost page with a input field and a button to submit to Firebase.
My Firebase code is:
var myRootRef = new Firebase('https://myappname.firebaseio.com/');
var childRef = myRootRef.child('users');
Then inside my click event I do:
childRef.push(_user);
This works but I end up with the following structure on Firebase:
{
"users" : {
"-J1aJh8xQCgYU23m5qWc" : "sdfsd",
"-J1aJQ1g5dw25SCGTLlq" : "ad",
"-J1aJPZET6j7Kn8-nIZR" : "ad",
"-J1aJg_ZchLeEVdnJnTb" : "adam",
"-J1aJQrC2T5CfT0bNgeY" : "aaa",
"-J1aJQTguxhvrMqcI4uU" : "dddd"
}
}
When what I want is:
{
"users" : {
"user" : "sdfsd",
"user" : "ad",
"user" : "ad",
"user" : "adam",
"user" : "aaa",
"user" : "dddd"
}
}
Reading the Docs it looks like I need to use setPriority but passing a number overwrites my previous data... How does one go about setting up saving like I desire? Thank you.
If you want human friendly names, you'll need to manually generate them. One way to do this is to create a counter, for example, in /lastUser. Every time you want to create a new user, you'll increment this counter using transaction, and then create the user by using set instead of push.
var myRootRef = new Firebase('https://myappname.firebaseio.com/');
var childRef = myRootRef.child('users');
var counterRef = myRootRef.child('lastUser');
counterRef.transaction(function(current) {
return current + 1;
}, function(err, committed, snapshot) {
if (!err && committed) {
childRef.child("user" + snapshot.val()).set("userdata");
}
});
For a more full fledged example check out https://gist.github.com/anantn/4323981, you can use the same approach to generate human friendly userIDs as well.
Related
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)
}
})
I've got a question on how to combine data from different Firebase database nodes before displaying it on the frontend. I've got a Firebase database with the following structure. (I'm new to a nosql setup, so this looks more relational):
{
"agents" : {
"-KPCmnwzjd8CeSdrU3As" : {
"contactNumber" : "12345",
"name" : "aaa"
},
"-KPCmw6dKuopDlsMVOlU" : {
"contactNumber" : "123",
"name" : "bbb"
},
"-KPCoWcLecpchcFV-vh_" : {
"contactNumber" : "123",
"name" : "ccc"
},
"-KPROMhPatLjVxMdvfLf" : {
"contactNumber" : "256342",
"name" : "blah"
},
"-KPWIFl5qp5FvAeC3YhG" : {
"contactNumber" : "123",
"name" : "eee"
}
},
"listings" : {
"-KPWKTvW3GzFEIT2hUNU" : {
"agent" : "-KPCoWcLecpchcFV-vh_",
"description" : "third",
"reference" : "REF1"
}
}
}
I'm using Firebase SDK 3.2.0 and AngularFire 2.0.1. In my Angular app I am able to get the list of listings, and for each one look up the agent information. The reason I'm not storing the agent info with the listing is I want the ability to update the agent and the change should reflect on all listings. I don't want to have to go and update all listings if the agent telephone number changes (as an example).
In my controller I have the following:
// get the listings
var listingsRef = firebase.database().ref().child('listings');
vm.listings = $firebaseArray(listingsRef);
// this will move to my ui-router as a resolve but for simplicity's sake
// I added it here...
vm.listings.$loaded().then(function(data){
// loop through the listings...
data.forEach(function(listing) {
if (listing.agent) {
// get the agent for the listing
listing.agent = AgentFactory.getAgent(listing.agent);
}
});
});
Right now the data is displaying correctly on the frontend. There is a slight delay with the agent data showing because of the need of the getAgent promise to resolve.
My questions are:
Is this the correct way of getting the agent data? Should I be looping through the listings and for each query the agent data? How do I wait / keep track of all of the getAgents to resolve?
Any help would be appreciated.
Thanks.
I've structured my data similarly. If you want to wait for all the getAgents to resolve you can use $q.all. I'm not entirely sure what your AgentFactory.getAgent is returning, but let's assume it's a $firebaseObject. If that's the case inject $q and then do the following:
vm.listings.$loaded().then(function (data) {
// loop through the listings...
var promises = [];
data.forEach(function (listing) {
if (listing.agent) {
// get the agent for the listing
listing.agent = AgentFactory.getAgent(listing.agent);
promises.push(listing.agent.$loaded());
}
});
return $q.all(promises);
}).then(function (agents) {
//all agents are loaded
});
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.
I'm a complete newbie, and I've been fiddling with the Meteor 1.0 sample todo list app to connect google oauth to it.
When I do so the page no longer renders properly because {{username}} is not set at all.
https://docs.meteor.com/#/full/meteor_users says "username: a unique String identifying the user." but the oauth stuff doesn't create one for you.
Connect service to existing meteor account talks about linking an already existing account to another service, but in this case I just want to use the external service.
https://stackoverflow.com/questions/25182903/meteor-facebook-registration uses onCreateUser() to manually set
user.username = user.services.facebook.name
but this isn't portable across services nor to guarantee uniqueness.
https://github.com/aldeed/meteor-collection2 defines the User schema so that username is mandatory.
When I dump the users table (some fields removed) the google account doesn't have a username, and there is no field that can really take on that value automatically as there could be a clash. Email could be used but I'd rather the username wasn't the email address. Do I just force the user to specify a desired username?
meteor:PRIMARY> db.users.find()
{
"_id" : "YNWt2cATMsKFG7od6",
"createdAt" : ISODate("2014-11-05T11:08:00.406Z"),
"services" : {
"password" : {
},
},
"username" : “a_user”
}
{
"_id" : "CyQsJqcez3kWTRHyQ",
"createdAt" : ISODate("2014-11-05T12:09:40.139Z"),
"profile" : {
"name" : “Alice User”
},
"services" : {
"google" : {
"email" : “a_user#example.com",
"family_name" : “User”,
"gender" : “female",
"given_name" : "Alice”,
"id" : "1115",
"name" : “Alice User,
}
}
}
What is the correct way of handling this?
This is how I did it myself with facebook and google
Accounts.onCreateUser(function (options, user) {
if (options && options.profile) {
user.profile = options.profile;
}
if (user.services) {
var service = _.pairs(user.services)[0];
var serviceName = service[0];
var serviceData = service[1];
console.log("serviceName", serviceName)
if (serviceName == "facebook") {
user.emails = [
{"address": serviceData.email, "verified": true}
];
user.profile = {"first_name": serviceData.first_name, "last_name": serviceData.last_name, "avatar": getFbPicture(serviceData.id)};
}
else if (serviceName == "google") {
user.emails = [
{"address": serviceData.email, "verified": true}
];
user.profile = {"first_name": serviceData.given_name, "last_name": serviceData.family_name, "avatar": getGooglePicture(serviceData.id)};
}
}
console.log("user created :", user)
return user;
});
I do not use username but I use email so that I'm sure that it will be unique. After that
I could allow the user to set his username or display name like Stackoverflow or other services do.
However you could use the email as username and again let the user change it later.
In my application, I am using this to handle the same problem.
username = user.services.facebook.name
user.username=generateUsername(username)
generateUsername = function(username) {
var count;
username = username.toLowerCase().trim().replace(" ", "");
count = Meteor.users.find({"profile.un": username}).count();
if (count === 0) {
return username;
}
else {
return username + (count + 1)
}
This is will create a unique username. After successful signup you can allow the users to change the username and check your db for its existence.
In my application I use
if(user.services.facebook)
this.user = user.services.facebook.name
if(user.services.google)
this.user = user.services.google.name
Right now I have a working messaging system developed in Meteor where users can send private messages to each other.
The server looks like this:
// .. lot of code
Meteor.publish("privateMessages", function () {
return PMs.find({ to: this.userId });
});
PMs.allow({
insert: function(user, obj) {
obj.from = user;
obj.to = Meteor.users.findOne({ username: obj.to })._id;
obj.read = false;
obj.date = new Date();
return true;
}
});
// .. other code
When the user subscribes to privateMessages, he gets a mongo object that looks like this:
{ "to" : "LStjrAzn8rzWp9kbr", "subject" : "test", "message" : "This is a test", "read" : false, "date" : ISODate("2014-07-05T13:37:20.559Z"), "from" : "sXEre4w2y55SH8Rtv", "_id" : "XBmu6DWk4q9srdCC2" }
How can I change the object to return the username instead of the user id?
You need to do so in a way similar to how you changed username to _id. You can create a utility function:
var usernameById = function(_id) {
var user = Meteor.users.findOne(_id);
return user && user.username;
};
Edit:
If you don't want to poll minimongo for each message, just include username instead of _id inside your message object. Since username is unique, they will be enough.
If in your app you allow users to change username, it might be a good idea to also keep the _id for the record.
In one of larger apps I've been working with we kept user's _id in the model (to create links to profile etc.), as well as cached his profile.name (for display purposes).
I suggest adding the collection helpers package from atmosphere. Then create a helper for PMs called toUser that returns the appropriate user.
Then you can get the name using message.user.name.