I am new to Firebase and I am trying to explore it. I already know i can make a reference to database and pull some data like: firstName, email etc. However, I have a function for uploading images to storage. I have a reference to storage but i cannot find function for storage similar to the one for database so i can pull images or their names:
DataService.instance.usersRef.observeSingleEvent(of: .value) { (snapshot: DataSnapshot) in }
Any help would be appreciated.
Related
I know I can use CloudKit publicDatabase and create a records shared between all users of my app. But I actually need the sama public database, but for KeyValueStorage. Something like public UserDefaults in iCloud. Is it possible?
My store is initialized like this:
let keyValueStore = NSUbiquitousKeyValueStore.default
but this is only for current user container, not publc.
NSUbiquitousKeyValueStore and CloudKit databases are completely unrelated. (Besides the fact, they are both cloud storage. :-)
If you need something like NSUbiquitousKeyValueStore in the public CloudKit database, you need to simulate this by yourself. For example by serialising the dictionary into a single Data object and store this object or have a record type (key, value) which is filled accordingly.
I am attempting to build a tableview that displays the users who have liked the current user's posts. For example, "John Smith, Tom Jones, and Sally Hughes liked your post (display image of post in cell". I think I'm on the right track but I'm wondering if my data structure is going to make this unnecessarily difficult or if there is an easier way.
My Firestore data structure is just below. The "BmV..." is the userId, "-M0e..." is the postId, and the "Ff0..." and "nIh..." are the users who have liked the post.
"likeActivity" : {
"BmvRlWWuGRWApqFvtT8mXQlDWzz2" : {
"-M0efUXcZy43fDVXjTvT" : {
"Ff0CxZhQzYVHuqbnsiOKwRAB01D2" : true,
"nIhx1SnChjapy4cbrD5sC1WIZXM2" : true
}
},
}
My first question is if this is the best way to structure this data? Then, In the ActivityViewController using the following code to retrieve of the current user's posts with activity.
var activityDict = [String: [Any]]()
let newActivity = DataService.ds.REF_LIKE_ACTIVITY.child("\(uid)")
//print("NEW POST - \(newPost)")
newActivity.observe(.value, with: { (snapshot) in
self.posts = []
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshot {
print("ACTIVITY -- \(snap.key)")
let userLikeData = DataService.ds.REF_LIKE_ACTIVITY.child("\(uid)").child(snap.key)
userLikeData.observe(.value, with: { (snapshot) in
self.posts.append(snap.key)
print("SNAPSHOT VALUE -- \(snapshot)")
if self.activityDict["\(snap.key)"] != nil {
self.activityDict["\(snap.key)"]!.append(snapshot.value!)
} else {
self.activityDict["\(snap.key)"] = [snapshot.value!]
}
self.activityTableView.reloadData()
})
}
}
})
My next question is if the activity should be accumulated in an array of dictionaries like I have it? Is there a better way to organize this data?
My first question is if this is the best way to structure this data?
When using NoSQL databases there is no singular "best" way to store data. You'll instead store the data in a way that best supports your use-cases. And since you'll typically uncover more (details about your) use-cases as you implement and evolve your app, you data model evolves (adapting and expanding) with it.
I recommend reading NoSQL data modeling, and watching Firebase for SQL developers and Getting to know Cloud Firestore. The last one is for Cloud Firestore, but many of the techniques Todd discusses apply equally to other NoSQL databases.
should [the activies] be accumulated in an array of dictionaries like I have it?"
If that works for your use-cases, then it sounds fine.
The only thing of note is that you're using observe, which attaches a permanent listener, and then append the updated snapshot data to the array. This means that if an activity gets changed in the database, your closure will get called again with a snapshot for that activity.
This is great, because it allows you to show the updated activity in the UI. But since you're appending it to the array, you'll end up displaying the activity twice: once as it was stored in the database when you first loaded it, and then again as it exists after the update. If that is what you're aiming for then 👍, but it is more common to update the existing data in the array, instead of adding the updated data as a new item.
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.
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.
My app is a directory with basic things like phone numbers and locations. There's going to be many entries and I will have to update the database on a weekly basis and I don't want to rely on my users to update their app using the App store, so I want the data to be updated whenever they connect to the internet, but I want all of the data stored locally so they can use it even if they don't have internet access. For my first app, it's proving to be quite tricky :)
I think I'll have to use Parse so I can update the database whenever I need to, along with something like Realm (https://realm.io/) or Core Data (hopefully not Core Data :( ). I read about Parse's Local DataStore, and if there's a way to make it work for my needs I'd definitely use it. I like the simplicity of Realm though and if I there's a way to make it work with Parse, that would be the route I'd want to take.
Can somebody show me an example on how they might go about doing this? If the PFObject or RLMObject is called person and has two strings (phone number and name, how would you get that from Parse.com to the device (local storage)?
This is an extra and I don't even know if it's possible*
While the app is downloading from the App Store, could it download the data from Parse? As in, the second the user opens the app, even if they no longer have internet access, the data is locally stored and usable to them.
(I only know Swift but may be able to understand obj-c if anybody cares to show me some code snippets)
Any help at all would be greatly appreciated :)
Joe from Realm here.
First to retreive an object from Parse you will need to do this:
var query = PFQuery(className:"GameScore")
query.whereKey("playerName", equalTo:"Sean Plott")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
println(object.objectId)
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
You can read more about this here
Once you retrieve your objects, I would loop through them as you see here
for object in objects {
println(object.objectId)
}
And then I would use Realm's Realm().create(_:value:update:)(shown in code below). You need to make sure you have a primary key to use this though (I would use parse's objectId as the primary key in Realm). Here is how you set a primary key in Realm.
An example of how I would import them into Realm would be something like this (Where Venue is the class of the way the object is stored in Realm):
let realm = Realm()
realm.write {
for object in objects {
realm.create(Venue.self, value: object, update: true)
}
}
You can read more about importing here
Lastly the logic of when you do this is up to you. You could do it each time the person opens the app. One thing with syncing local databases with the ones on the server is that it's good to just check another Table maybe called LastUpdated. This table will let you know if you need to update your local database. Overall it's a very manual process but it depends on the situation and how you want to structure your app.