Can't get list of users [duplicate] - ios

This question already has answers here:
How do I return a list of users if I use the Firebase simple username & password authentication
(7 answers)
Closed 6 years ago.
I want to show list of users in my app. I use default Auth system from firebase. But response always empty.
FIRDatabase.database().reference().child("users").queryOrdered(byChild: "email").observe(.value, with: { snapshot in
print(snapshot)
})
But snapshot is always Snap (users) <null>

The Firebase Authentication system does not automatically insert anything into the Firebase Database. I guess your database is empty, which is the reason for snapshot being null.
Your code looks correct, but as I said there might not be any data in your database to receive.
Depending on what exactly you want to achieve you should consider storing user meta data in you database. A good point to do so would be directly after the user creation.

Registering a user with Firebase Authentication, by default, does nothing to modify your Firebase Database. Authentication and Database are two pretty much unrelated services. It's a common practice, once you register a user, to save an entry in your Database with their uid, so you can relate the two services:
let auth: FIRAuth? = FIRAuth.auth() // The authentication object
auth?.createUser(withEmail: email, password: password) { (user, error) in
// If registration was successful, `user` is a FIRUser with a uid
if let userId = user?.uid {
let exampleDBPath = FIRDatabase.database().child("users").child(userId)
// Write the user object, for instance a user name or other data, to this path
exampleDBPath.setValue(someJSONAboutTheUser) { (error, result) in
// Now you have a spot to modify your user in the database
}
}
}
This FIRUser created from registration is the same type of object you'll get when a user tries to sign in, so you can find the correct user in the database via the same uid.

Related

How can I use user input to name a child in Firebase?

I'm trying to create a simple user database on Firebase for iOS. I have two textfields, one that takes the user's email address, and the other that takes the user's password. I want the email to be the user's uid. I try to accomplish this by creating a variable called "email" which I set equal to emailTextField.text! Then I implement the code that generates child(s) in Firebase, like so:
ref = Database.database().reference()
ref.child("users").child(email).setValue(true)
Here's my problem: creating a child and naming it using a variable, doesn't work. I can do the following just fine:
ref.child("users").child("email")
but once I take away the quotation marks around "email" so that it becomes the variable, the program crashes.
How can I use user input to name a child in Firebase?
Firebase node / document names do not support the same character set which email addresses support, for example, the . symbol in an email address would make the child name invalid.
If you tried setting a child as
ref.child("users").child("xyz#xyz.xyz")
you should see the same error.
If you absolutely need to use the email address as the node name, I recommend encoding the email in a way which is compatible with the firebase node name rules.
Link to the rules
Edit: If you are using firebase auth, the normal pattern is too use the UID returned by the authenticated user object as the node name, not the email address entered from the textfield.
A quick example:
Auth.auth().signIn(withEmail: email, password: password) { (user, error) in
if let user = user {
ref.child("users").child(user.uid).setValue(true)
}
}

Firebase client side UID and Firebase function UID do not match

I am trying to use Stripe with Firebase and have followed along the linked Firestripe example project. When a user signs up for the app, the following function is triggered in Firebase which creates a Customer object in Stripe.
exports.createStripeCustomer = functions.auth.user().onCreate(event => {
const data = event.data;
return stripe.customers.create({
}).then(customer => {
return admin.database().ref(`/stripe_customers/${data.uid}/customer_id`).set(customer.id);
});
});
The last line in the function above is supposed to write the Stripe customer ID as a child of the Firebase UID in the database which it does successfully.
Now on the client side (iOS - Swift) when trying to write to the same authenticated user by obtaining their UID using the following:
let userID = Auth.auth().currentUser!.uid
Database.database().reference(fromURL: "https://REDACTED.firebaseio.com/").child("stripe_customers").child(uid).child("sources").setValue([
"token": token.tokenId,
])
it creates a whole different child under /stripe_customers/ meaning the UIDs don't match...
How do I go on obtaining the real UID of the user from the client side? Or am I doing something wrong? Any help or insight would be appreciated.
What you're doing in the first code sample is storing data under Stripe customer ID while in your second code sample, you're attempting to retrieve data based on your Firebase UID.
What you want to do is store user objects named as your Firebase UID, then store your Stripe ID in a child object. Finally, query for your Firebase UID object not its Stripe ID child.
Furthermore, I can't see you using your let userID = Auth.auth().currentUser!.uid
anywhere in your query. If you declare a constant that you're not using for your example, it's better to leave it out.
Let me know if you need more help.
Also, have a look at Firebase's new Cloud Firestore.
It's still in beta, but it's extremely powerful compared to Firebase Realtime Database.

observeSingleEvent(of:with:) fetching old data

Background:
I have an app where new users complete a sign-up form (consisting of a username, email, and a password) to register for an account. When the new user submits the form, the app checks its Firebase Database to see if the username has already been taken. The problem here is that observeSingleEvent(of:with:) is not getting the newest data. When I update the data directly from the Firebase console, the changes are not reflected back in the returned results of observeSingleEvent(of:with:). Even between app restarts, the new data changes are not returned.
The only thing I've seen on the issue is here. A user says not to have persistence enabled when using observeSingleEvent(of:with:). But, I have persistence disabled. Also, I set the keepSynced() on the FIRDatabase instance to false (and I've tried true as well). No luck with either setting.
Here's an example of what I am trying:
let usersDatabaseReference = FIRDatabase.database().reference().child("users")
usersDatabaseReference.keepSynced(false)
// Query the database to see if the username is available
// The user with the username "mark" was removed from the database via the Firebase console
let username = "mark" // This user used to exist in the database (and was previously added through the app).
usersDatabaseReference.child(username).observeSingleEvent(of: .value, with: { (snapshot) in ... } )
The above code block should return the newest data (one where the user "mark" should not exist).
I am wondering if anyone else ran into this problem, or if anyone has possible solutions.
Note: Developing using iOS 10.1 and swift 3.
the observeSingleEvent(of:with:) return the value only one time
try this :
refHandle = postRef.observe(FIRDataEventType.value, with: { (snapshot) in
let postDict = snapshot.value as? [String : AnyObject] ?? [:]
// ...
})
this will add a listener on database event link
I recommend you refactor your JSON data model using the username as key. Doing this, you should get an error when trying to create a duplicate user in the database.
So, my problem had nothing to do with caching or fetching old results. Some of my code logic depended on checking the value of the snapshot parameter that was passed back in the completion handler for observeSingleEvent(of:with:). I wrongly assumed that I could check for a null database value by comparing it with nil; this led to a misinterpretation of results.
The best way to actually check for a null database fetch is by calling the exists() method on a FIRDataSnapshot instance. exists() returns true if the snapshot contains a non-null value.

How to get Firebase User (fb auth) directly? (without realtime db ref) [duplicate]

This question already has answers here:
How do I return a list of users if I use the Firebase simple username & password authentication
(7 answers)
Closed 6 years ago.
I'm making an application with a Message object which has sender and receiver properties.
I'd like to assign these properties Users that live in the Auth' tab of Firebase Console (fb auth-ed).
Since my application's functionality only needs to read data from the users, I thought I don't need to add them to the realtime database, just access them through FIRAuth (which I'm assuming is the internal representation of the Auth' tab on Firebase Console).
I can get the 'current user' like this:
FIRAuth.auth()?.currentUser
And this will be the 'sender' property of a Message.
But for the 'receiver' property I want to grab a User (that the sender will choose from a drop down of fb contacts) from the fb auth-ed ones listed in the Auth' tab of Firebase Console. For recipient, I need to be able to do something like this (pseudocode):
users.find(where uid == current_user.uid)
Is it possible to do this directly without User table(s) in database? Do I really need to copy over entries from Firebase Auth to Firebase Database? Shouldn't there be a better way to get non current users from Firebase? Does anyone else think that's really bad design (for just being able to read an entry)? Aren't I then responsible for the maintenance of those entries?
Appreciate pointers to specific reading too!
For clarity, I'm not trying to query an entry in the realtime database tab of Firebase Console. I'm trying to query the User object that Firebase saves from Facebook (which is visible in Auth' tab of Firebase Console).
To access the other users make your JSON structure like this:-
Users:{
userID1 : {...//PERSONAL DATA},
userID2 : {...//PERSONAL DATA},
userID3 : {...//PERSONAL DATA}
},
users_Data:{
userID1 : {...//data to be shared like userID, name..etc},
userID2 : {...//data to be shared like userID, name..etc},
userID3 : {...//data to be shared like userID, name..etc}
}
Just access those users_Data to store in your dataSource in which you will have your usersID's to access.

Anonymously login auto generated user

I see that objectId of users generated locally and users created after anonymous login are not the same.
For example
PFUser.enableAutomaticUser()
let localUser = PFUser.currentUser()!.objectId!
print(localUserId) // "obj1"
PFAnonymousUtils.logInWithBlock {
(user: PFUser?, error: NSError?) -> Void in
let annonUserId: String = PFUser.currentUser()!.objectId!
print(annonUserId) // obj2
}
I want that obj1 to persist throughout the anonymous login phase.
Can I somehow "attach" the locally created user and login him anonymously? or is auto generated users are only useful for when you later upgrade him to a user&pass / social based logins ?
PFAnonymousUtils.logInWithBlock is defined to destroy existing anonymous user data and create a new clean anonymous user. You should only do that when the user is logged out.
If you enable anonymous users then one will be created initially and you can add whatever details you want to that. Then, later, when the user wants a real account use signUp: on the PFUser to convert it.
Note that anonymous users aren't real, you can't use them for everything. So, you may have some issues with them actually participating with other users. If this is the case then you may need to create real placeholder users with auto-generated login details and convert that at a later date by updating the username and sending a forgotten password e-mail (or similar).

Resources