I have some information being sent to firebase. In my app, users enter info about themselves and it's stored under the uids. Here is the hierarchy:
{
"gJRhIOfmckTq9cRWNnwhg7tdxxv1" : {
"City" : "New York, New York",
"College" : "New York University of New York",
"Major" : "Nursing",
"uid" : "gJRhIOfmckTq9cRWNnwhg7tdxxv1"
},
"ix7JSoW5JZMSmDjwQRUUd8W7fi2" : {
"City" : "Miami, Florida",
"College" : "University of Miami",
"Major" : "Neuroscience ",
"uid" : "ix7JSoW5JZMSmDjwQRUUd8W7fi2"
}
}
Here is the path to uploading the data:
FIRDatabase.database().reference().child("info").child(self.loggedInUser!.uid)
.observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
The issue is that when a particular user is logged in, they should be able to see other user's information but when I try to retrieve the not logged in user's information, I run into a problem because of the uid. I get only the logged in user's information displayed in the non-logged in user information page. How can I make .child(self.loggedInUser!.uid)so that it does not only capture the logged in user's uid but all uids.
Based on your response to my comment, it seems like you need all of the information about a user when, say, their profile is selected. This is where denormalization will come in handy. This blog post and this YouTube video go into detail on the what and why of denormalization, so I won't get into that too much here.
Using denormalization, you could include a child that lists all users with a username as a key and the user's uid as the value. Then when a user selects that user by username, say from a list in a table, you can find the user's uid and then listen to the value of the user's profile. The database structure would be something like this:
{
users: {
"thisperson": "gJRhIOfmckTq9cRWNnwhg7tdxxv1",
"anotherperson": "ix7JSoW5JZMSmDjwQRUUd8W7fi2",
...
},
info: {
"gJRhIOfmckTq9cRWNnwhg7tdxxv1" : {
"City" : "New York, New York",
"College" : "New York University of New York",
"Major" : "Nursing",
"uid" : "gJRhIOfmckTq9cRWNnwhg7tdxxv1"
},
"ix7JSoW5JZMSmDjwQRUUd8W7fi2" : {
"City" : "Miami, Florida",
"College" : "University of Miami",
"Major" : "Neuroscience ",
"uid" : "ix7JSoW5JZMSmDjwQRUUd8W7fi2"
},
...
}
}
Then instead of listening to the values for the logged in user, you listen for the value of the selected user's uid, then listen using that instead:
FIRDatabase.database().reference().child("info").child(otheruid)
.observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
Where otheruid is the value of FIRDatabase.database().reference().child("users").child(username)
Related
I want to retrieve data uid in User table data but for a specific user , I have 2 users, and it seems that it grabs the 2 users uid but I want to grab with i speficy not both of them just one.
Thank You In advance
let specificDatabase = Database.database().reference()
specificDatabase.queryOrdered(byChild: "User/FirstName").queryEqual(toValue: "The user first name")
specificDatabase.observeSingleEvent(of: .value) { (snapShot: DataSnapshot) in
for child in snapShot.children {
print(snapShot.key)
}
}
Firebase Data Structure
"User" : {
"ez8sTAsqXTWfnuzizUXU69VS4qM2" : {
"FirstName" : "other",
"LastName" : "Martin",
"uid" : "ez8sTAsqXTWfnuzizUXU69VS4qM2"
},
}
"Data" : {
"ez8sTAsqXTWfnuzizUXU69VS4qM2" : {
"-Ll7jUYg6BxRAhWPLskg" : {
"Name" : "other Martin",
"Data1" : "data"
},
"-Ll7jW_elQIPTLESwDYD" : {
"Name" : "other Martin",
"Data1" : "data "
}
},
}
You're telling Firebase to order each child node of the root by its User/FirstName property and then filter on that. Since the child nodes of the root don't have a property at that path, the query returns no results.
Instead you want to order/filter each child node of /User by itsFirstName property, which you can do with:
let specificDatabase = Database.database().reference(withPath: "User")
specificDatabase.queryOrdered(byChild: "FirstName").queryEqual(toValue: "other")
We have an iOS application that grabs model data from an API. The user of the iOS device performs actions that link up the model data and creates relationships between them. The iOS then submits back to the API to save the relationship and allow for the relationship to be viewable in the web application.
The JSON payload has the potentially of being large if all the objects that were associated with the new relationship are submitted with their attributes.
"peoples_vehicles": [
{
"owner" : {
"id" : 8282, <----------this would be a UUID
"name" : "John Smith",
"address": "123 Fake Street",
},
"vehicles" : [
{
"id" : 1234, <----------this would be a UUID
"name" : "FORD F150",
"make" : "F150",
"model" : "FORD",
"year" : "2017",
},
{
"id" : 5678, <----------this would be a UUID
"name" : "FORD ESCAPE",
"make" : "ESCAPE",
"model" : "FORD",
"year" : "2013",
}
]
},
{
... another person with their vehicles
}
]
Since the data being sent back is all data that was originally from the API, should the iOS application even bother sending all the attributes back? Should the iOS application simply send back all the relationships with only the objects ids? We use UUIDs
"peoples_vehicles": [
{
"owner" : {
"id" : 8282, <----------this would be a UUID
},
"vehicles" : [
{
"id" : 1234, <----------this would be a UUID
},
{
"id" : 5678, <----------this would be a UUID
}
]
},
{
... another person with their vehicles
}
]
We seem to be leaning more towards just sending ID for pre-existing data. It makes the submit payload from iOS to API have very few attributes that are actually strings (none in this example).
There are cases when we would have to create new custom objects. In that case, all the attributes would be sent over and the ID of this new object would be null to indicate that this object has to be created.
"peoples_vehicles": [
{
"owner" : {
"id" : 8282, <----this would be a pre-existing object
},
"vehicles" : [
{
"id" : 1234, <----this would be a pre-existing object
},
{
"id": null <----new object that needs to be saved
"name" : "FORD F150",
"make" : "F150",
"model" : "FORD",
"year" : "2017",
}
]
},
{
... another person with their vehicles
}
]
Would this be a decent approach? Looking at Stripe and Shopify API as examples, this seems to work nicely, but I wanted to make sure I wasn't missing anything and if I should be included the attributes for objects that are pre-existing.
Each user has a conversation node, each time a new conversation has a new message I need to update both conversation nodes for the two user involved in the conversation, I want just to update the "lastMessage" and "tinestamp" fields here is my try:
let fanoutObject = [userPath : dataToUpdate,
otherUserPath : dataToUpdate]
K.FirebaseRef.root.updateChildValues(fanoutObject)
where the paths for each user is:
"/users/{userID}/conversations/{conversationID}"
and the dataToUpdate:
let dataToUpdate:[String:AnyObject] = ["timestamp" : message.timestamp,
"lastMessage": message.textBody]
Result:
The node conversations for each user is updated BUT other fields in the conversation node are removed !
the conversation node fro each user is:
"conversations" : {
"{conversationID}" : {
"lastMessage" : "your name ?",
"seen" : true,
"timestamp" : 1467849600000,
"with" : {
"country" : "US",
"firstName" : "John",
"profileImage" : "https://..."
}
}
}
note that the node conversations is inside a node user which is an element inside the root node users
and after update it's :
"conversations" : {
"{conversationID}" : {
"lastMessage" : "your name ?",
"timestamp" : 1467849600000,
}
}
but I was expecting just to update the two values and keep others ?
According to docs my code should works:
updateChildValues Update some of the keys for a defined path without
replacing all of the data.
It's a bit hard to parse your code, but most likely it's the behavior of updateChildValues() that is confusing you.
When you call updateChildValues(), the Firebase server will loop over the object that you pass in. For each path in there, it will replace the entire value at that path with the value from that you passed in.
So if your current JSON is:
{
"Users": {
"uidForUser1": {
"name": "iOSGeek",
"id": 2305342
},
"uidForUser2": {
"name": "Frank van Puffelen",
"id": 209103
}
}
And the update is (in JSON format, the lingua franca of the Firebase Database):
{
"users/uidForUser2/name": "puf",
"users/uidForUser1/name": "My actual name"
}
Your resultant JSON will be:
{
"Users": {
"uidForUser1": {
"name": "My actual name",
"id": 2305342
},
"uidForUser2": {
"name": "puf",
"id": 209103
}
}
But if you send the following update:
{
"users/uidForUser1": {
"name": "My actual name"
},
"users/uidForUser2": {
"name": "puf"
}
}
The resulting JSON will be:
{
"Users": {
"uidForUser1": {
"name": "My actual name"
},
"uidForUser2": {
"name": "puf"
}
}
Update
To update two fields in the same object, but leave the other fields unmodified:
{
"path/to/object/field1": "new value",
"path/to/object/field2": "new value2"
}
Alternatively, you can update the lastMessage and timeStamp data by replacing the old values by providing full path :
let lastMessagePath = "/users/{userID}/conversations/{conversationID}/lastMessage"
let lastTimeStampPath = "/users/{userID}/conversations/{conversationID}/timestamp"
K.FirebaseRef.child(lastMessagePath).setValue(message.timestamp)
K.FirebaseRef.child(lastTimeStampPath).setValue(message.textBody)
I'm trying to do an inner join on a FIRDatabaseQuery object.
below is the database structure. I have some posts that are linked to post-comments. I am trying to get all the posts that a specific user added a comment on:
{
"posts" : {
"-KIycKhZU55dmKnHbbxv" : {
"author" : "John Doe",
"body" : "This is a post test",
"title" : "test",
"uid" : "SHaH36BLwgPvwgi9cDmRnsnONFB2"
},
"-KIyg_ks1O5QL4_4dfq_" : {
"author" : "Jane Doe",
"body" : "This is a post test",
"title" : "test2",
"uid" : "x5leSBGArnd10JilD9YDyNBNfZ03"
},...
}
"post-comments" : {
"-KIycKhZU55dmKnHbbxv" : {
"-KIycMyL0Vy1BHVdI4zc" : {
"author" : "toto",
"text" : "test",
"uid" : "SHaH36BLwgPvwgi9cDmRnsnONFB2"
},
"-KIyg_ks1O5QL4_4dfq_" : {
"author" : "toto",
"text" : "test",
"uid" : "SHaH36BLwgPvwgi9cDmRnsnONFB2"
}
},...
}
in SQL this will be translated into a inner join query similar to:
Select * from post inner join post-comments on post-id where post-comments.uid = "user id"
Does anybody know how o get something similar to an inner join in firebase?
Thanks a lot,
Yacine
You may want to consider
"posts" : {
"-KIycKhZU55dmKnHbbxv" : {
"author" : "John Doe",
"body" : "This is a post test",
"title" : "test",
"uid" : "SHaH36BLwgPvwgi9cDmRnsnONFB2"
"commented_by"
"SHaH36BLwgPvwgi9cDmRnsnONFB2": true
Then you can simply query for
posts.child("commented_by/uid").queryEqualToValue(true)
or, change the post-comments around to better match the queries you want to do:
"post-comments" : {
"-KIycMyL0Vy1BHVdI4zc" : {
"author" : "toto",
"post_data":
post_id: "-KIycKhZU55dmKnHbbxv",
post_title: "test"
"text" : "test",
"uid" : "SHaH36BLwgPvwgi9cDmRnsnONFB2"
},
That makes the query a snap as the post-comments node can be queried for the uid which return all of the post_id's of the posts they commented on. It wouldn't return the post itself, however, you may just be looking for the title so you can populate a list. Once the user taps it clicks it you can retrieve the actual data.
You will need to work with nested firebase calls. You can find a javascript example in this question but your swift code should look like the following:
ref.child("posts").observeEventType(.ChildAdded, withBlock: { (snapshot) in
if let postId = snapshot.key as! String {
let commentsRef = ref.child("post-comments")
commentsRef.child(postId).queryOrderedByChild("uid").queryEqualToValue(userId).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
for child in snapshot.children.allObjects as [FDataSnapshot] {
print(child.value)
}
}) { (error) in
print(error.localizedDescription)
}
}
})
The JSON:
{
"coffee-shops" : {
"-KJ4I4D-Jrqrzc9wP42C" : {
"coffeeShopName" : "Starbucks",
"coffeeShopRating" : 3.5,
"-KJ4VVB51wx9NpEKtjxQ" : {
"coffeeShopName" : "Starbucks",
"coffeeShopRating" : 1,
"coffeeShopReview" : "R",
"coffeeShopReviewerName" : "Charles"
},
"-KJEJ6MpQwOHcay_9k6v" : {
"coffeeShopName" : "Starbucks",
"coffeeShopRating" : 4,
"coffeeShopReview" : "B",
"coffeeShopReviewerName" : "Charles"
}
}
},
"users" : {
"02a54e06-9635-4e22-9bb7-c0ddcd9c6f4f" : {
"email" : "charles#gmail.com",
"provider" : "password",
"username" : "thecoffeeguy"
},
"03fe2c17-3c66-442c-a63d-4a1e02fd660c" : {
"email" : "test#gmail.com",
"provider" : "password",
"username" : "Charles"
},
"16a7279f-5478-4f3f-b5f8-2f261d166d92" : {
"email" : "tester#gmail.com",
"provider" : "password",
"username" : "haha"
},
"23275f65-8e16-4ede-9236-21485b7493b9" : {
"email" : "boo#gmail.com",
"provider" : "password",
"username" : "boo"
},
"a5ed6962-76bc-476a-b432-6787e45badfc" : {
"email" : "mesbekmek#gmail.com",
"provider" : "password",
"username" : "mesbekmek"
}
}
}
Some context: I'm making a coffee app and I need to have the reviews be specific to the coffee shop a user is at. Right now, all reviews that have ever been made will show up on my tableview.
This isn't so much a "how to code" question, but me wondering how to approach this and how I might solve it.
This is what I think I should do:
get a specific coffee shop's uuid
iterate over the reviews because they are sub-entries in my coffee shop model
get data from iterating over the reviews, then see if the uuid of the cell(?) selected matches the review uuid
This doesn't really sound right to me, so any help would be great.
You can organize your db in a different way.
coffee-shops:
|--coffeeId1
|--coffeeId2
|--coffeeId3
reviews:
|--coffeeId1
|----reviewId1
|----reviewId2
|--coffeeId2
|----reviewIdX
|----reviewIdXx
When you insert a review you can use the same key of the coffee-shop.
In this way all the reviews of the same coffee shop is under the same ref.
You can achieve it using something like this:
ref(reviews).child(coffeeshop.getKey()).push();