I am trying to allow users to start games with and follow other users by searching their username. I need to be able to make sure that a user with that username exists. I was using the following code but although the if is called the else does not get called when it should.
let checkWaitingRef = Firebase(url:"https://test.firebaseio.com/users")
checkWaitingRef.queryOrderedByChild("username").queryEqualToValue("\(username!)")
.observeEventType(.ChildAdded, withBlock: { snapshot in
if snapshot.value.valueForKey("username")! as! String == username! {
} else {
}
JSON data tree
{
"097ca4a4-563f-4867ghj0-6209288bd7f02" : {
"email" : "test1#tes1.com",
"uid" : "097ca4a4-563f-4867ghj0-6209288bd7f02",
"username" : "test1",
"waiting" : "0"
},
"55a8f979-ad0d-438u989u69-aa4a-45adb16175e7" : {
"email" : "test2#test2.com",
"uid" : "55a8f979-ad0d-438u989u69-aa4a-45adb16175e7",
"username" : "test2",
"waiting" : "0"
}
}
Easy fix:
Don't use .childAdded as the block will not execute when the query doesn't find anything.
Instead use .Value and check for NSNull
let checkWaitingRef = Firebase(url:"https://test.firebaseio.com/users")
checkWaitingRef.queryOrderedByChild("username").queryEqualToValue("\(username!)")
.observeEventType(.Value, withBlock: { snapshot in
if ( snapshot.value is NSNull ) {
print("not found)")
} else {
print(snapshot.value)
}
})
Related
I am trying to return the count of posts for a specific user where a field contains a certain value. The structure I am using in Firebase is here:
{
"posts" : {
"-Lyzpsb1hH4LUPvcXE3H" : {
"beverageCategory" : "Beer",
"beverageName" : "Dortmunder",
"beveragePrice" : "3.99",
"beverageRating" : 3,
"beverageType" : "Lager",
"imageUrl" : "https://firebasestorage.googleapis.com/v0/b/socialspirit-37cae.appspot.com/o/post-pics%2F3C23E923-A3BD-4393-B3EF-8F939D8B08B8?alt=media&token=ac80cb98-f2a1-4197-b328-2a69a2ac1fd1",
"wineVintage" : ""
}
},
"user" : "sdkjvksdjf",
"users" : {
"0hyN8N2klJWqPi2lkRqNK3vg7z63" : {
"posts" : {
"-Ly6ciYHm7v5JFy1VmVY" : true,
"-Ly6cyLukI6aRRki5yna" : true
},
"provider" : "Firebase"
},
"26OUuaRZEVWUmkLJp13LzirGbs13" : {
"posts" : {
"-Ly6fGmQEMZz3c-azMnJ" : true
},
"provider" : "Firebase"
},
"5r6FulsvIRap7pLK5D3zV8qyPVv1" : {
"provider" : "Firebase"
},
"gQpktBMh97hTqiysHBwvVLZl70y1" : {
"posts" : {
"-Lyzpsb1hH4LUPvcXE3H" : true,
"-LyzqFgvmrBgdsgKSt_5" : true,
"-Lz-fIMDal00ex3_viQo" : true,
"-Lz-lXsSBqKlcf8hBext" : true,
"-Lz2eNLfk1PFEVkEgmwa" : true,
"-Lz2etF0UqFqLkdGOR13" : true,
"-Lz2fGUi0qzJtniNr5LX" : true,
"-Lz2gP5c47yHDO2g0ljr" : true,
"-Lz2gdhfedZfTtzjP2ee" : true,
"-Lz2gllC3caXgPf2VAPU" : true,
"-Lz2hH8FbNmBEOLcHCJz" : true,
"-Lz2jzkXuEZ3Cfe96eGW" : true,
"-Lz3RvuW4fMXarhW7vLv" : true,
"-Lz3S8YA0vgk4ZrjL_Kk" : true
},
"provider" : "Firebase"
}
}
}
I am using the following code to get the count of records that have a beverageCategory of "Beer".
DataService.ds.REF_USERS.child("\(uid)").child("posts").child("beverageCategory")
.queryOrderedByValue().queryEqual(toValue: "Beer")
.observe(DataEventType.value, with: { (snapshot) in
print("SNAP - \(snapshot.childrenCount)")
})
The childrenCount returns 0, however. Any idea what I'm doing wrong here? Thanks!
EDIT: I added the JSON for the data structure and I think I left an important detail out. The data structure actually has users that have posts and the associated postid that links back to posts. I think what I have to do is first find the user's posts and then of those posts get a total count for each category. I'm guessing that is slightly different than the methods I tried. Any ideas on that?
EDIT 2: So my issues is that users and posts are in different structures. I need to find all of the user's posts and iterate through them to see if what the beverageCategory is. I have done that with the following code. The issue with the code below is that the count is doubled when I add a post and then open the menu. But when I exit the menu and re-open the count is correct. Why is it double-counting?
func myFirebaseNetworkDataRequest(finished: #escaping () -> Void) {
beerCountArray.removeAll()
wineCountArray.removeAll()
liquorCountArray.removeAll()
print("BEER ARRAY \(beerCountArray.count)")
guard let uid = Auth.auth().currentUser?.uid else {
return
}
let newPost = DataService.ds.REF_USERS.child("\(uid)").child("posts")
newPost.observe(.value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
//print("SNAPSHOT - \(snapshot)")
for snap in snapshot {
let postData = DataService.ds.REF_POSTS.child(snap.key)
//print("SNAP KEY - \(snap.key)")
let bevCat = DataService.ds.REF_POSTS.child(snap.key).child("beverageCategory")
//print("BEV CAT - \(bevCat)")
postData.observe(.value, with: { (snapshot) in
if let postDict = snapshot.value as? Dictionary<String, AnyObject> {
let key = snapshot.key
let post = Post(postKey: key, postData: postDict)
//print("POST DICT - \(String(describing: postDict["beverageCategory"]!))")
if postDict["beverageCategory"]! as! String == "Beer" {
self.beerCountArray.append(1)
//print("BEER ARRAY LOOP - \(self.beerCountArray)")
}
if postDict["beverageCategory"]! as! String == "Wine"{
self.wineCountArray.append(1)
}
if postDict["beverageCategory"]! as! String == "Liquor" {
self.liquorCountArray.append(1)
}
//self.posts.append(post)
}
finished()
})
}
}
})
}
And...
override func viewDidLoad() {
super.viewDidLoad()
beerCountArray.removeAll()
wineCountArray.removeAll()
liquorCountArray.removeAll()
myFirebaseNetworkDataRequest {
//print("BEER ARRAY - \(self.beerCountArray.count)")
self.beerCount.text = String(self.beerCountArray.count)
self.liquorCount.text = String(self.liquorCountArray.count)
self.wineCount.text = String(self.wineCountArray.count)
}
}
Your query is not correct. Since you're trying to filter on a child property of each node under posts, you should call queryOrdered(byChild:).
So:
DataService.ds.REF_USERS.child("posts")
.queryOrdered(byChild: "beverageCategory")
.queryEqual(toValue: "Beer")
.observe(DataEventType.value, with: { (snapshot) in
print("SNAP - \(snapshot.childrenCount)")
})
Also see the Firebase documentation on ordering and filtering data.
I'm trying to code my own messenger. I saved the messages in Firebase database. I'm trying to access the messages with the normal way how I do it every time (database.database().reference().child("users")...., but it gives back only a few messages and only sometimes every message
I already tried it with .childAdded but it doesn't work either
func fetchMessages() {
self.messages.removeAll()
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference().child("users").child(uid).child("chats").child(self.chatuid).child("messages")
ref.observeSingleEvent(of: .value) { (snap) in
guard let data = snap.value as? [String: AnyObject] else { return }
//MARK: data = (messageID, AnyObject)
for (messageID, _) in data {
ref.child(messageID).observeSingleEvent(of: .value) { (snap2) in
guard let data2 = snap2.value as? [String: AnyObject] else { return }
//MARK: data2 = ("message": String, "sentuid": String)
guard let message = data2["message"] as? String else { return }
guard let sentuid = data2["sentuid"] as? String else { return }
let messageToAppend = Message(sentuid: sentuid, message: message)
self.messages.append(messageToAppend)
self.messageTableView.reloadData()
}
}
}
}
//self.messages = Place where I save my fetched messages
Firebase-Structure:
{
"users" : {
"V3bLZu61KYTCG0uCWV8LH1f4rRJ3" : {
"chats" : {
"x3GzxwmyLbXrQNNyBF2a82KqrHa2" : {
"messages" : {
"20191014165454" : {
"message" : "Heyho",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165647" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165754" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165800" : {
"message" : "Fuchsloch",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165805" : {
"message" : "Jlksaö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165808" : {
"message" : "Jadfsk",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165811" : {
"message" : "Jskldflsö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014170041" : {
"message" : "JALSF",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"test" : {
"messange" : "test",
"sentUid" : "MatesForSports"
}
}
}
},
"username" : "Acc2"
},
"x3GzxwmyLbXrQNNyBF2a82KqrHa2" : {
"chats" : {
"V3bLZu61KYTCG0uCWV8LH1f4rRJ3" : {
"messages" : {
"20191014165454" : {
"message" : "Heyho",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165647" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165754" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165800" : {
"message" : "Fuchsloch",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165805" : {
"message" : "Jlksaö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165808" : {
"message" : "Jadfsk",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165811" : {
"message" : "Jskldflsö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014170041" : {
"message" : "JALSF",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"test" : {
"messange" : "test",
"sentUid" : "MatesForSports"
}
}
}
},
"username" : "Acc1"
}
}
}
I expected that the code would give back around 10 messages, but it gives sometimes 5, sometimes 3 or even only 2 messages
My firebase-structure of the messages is .child("messages"), then a unique id, then the actual message and the sender at one layer
Here's an an answer followed by a suggestion.
Let's start with replicating your structure using some hard coded values
users
uid_0
chats
chat_uid_0
messages
unique_id_0
msg: "My Message"
sent_uid: "uid_1"
unique_id_1
msg: "Hello, World"
sent_uid: "uid_3"
unique_id_2
msg: "another message"
sent_uid: "uid_2"
then the code to read in the messages, iterate over them and print out the msg and sent_uid
func readMessages() {
let usersRef = self.ref.child("users")
let messagesRef = usersRef.child("uid_0").child("chats").child("chat_uid_0").child("messages")
messagesRef.observeSingleEvent(of: .value, with: { snapshot in
let allMessages = snapshot.children.allObjects as! [DataSnapshot]
for msg in allMessages {
let msgText = msg.childSnapshot(forPath: "msg").value as? String ?? "No Msg"
let sentUid = msg.childSnapshot(forPath: "sent_uid").value as? String ?? "No sender"
print(msgText, sentUid)
}
})
}
and the output is
My message uid_1
Hello, World uid_3
another message uid_2
That being said - your structure is way to deep and should be denormalized. While it may work, as soon as you want to query for items, of find messages posted by a specific user, it just doesn't work.
I don't know your full use case but this would be a better structure
users
uid_0
name: "Hank"
uid_1
name: "Leroy"
chats
uid_0
chat_id_0: true
chat_id_1: true
uid_1
chat_id_5: true
chat_id_0
unique_id_0
msg: "My Message"
sent_uid: "uid_1"
unique_id_1
msg: "Hello, World"
sent_uid: "uid_3"
unique_id_2
msg: "another message"
sent_uid: "uid_2"
With this structure, it's all very shallow and easy to get to data - perform queries etc. You can quickly retreive all chats that uid_0 is involved with, get any messages that uid_3 ever posted or add an observer to uid_1's chat so others are notified when a chat has been added. Again, this is just an example and may not fit your case but it's something to consider.
Is there a way to dynamically get a child database from the parent instance, without having to use childByAutoId () ?
{
"artists" : {
"artists_id_1" : {
"name" : "Atif Aslam",
"genre" : "Rock"
},
"artists_id_2" : {
"name" : "Arijit Singh",
"genre" : "Rock"
}
}
}
we usually refer to the path, and listener the items the DataBase...Example:
Database.database().reference().child("artists").child("artist_id_1").observeSingleEvent(of: .value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
print("\(String(describing: dictionary["name"] as? String))")
}
}, withCancel: nil)
it would only work for the first item. Because, it would not be dynamic. What is normally used is the following example below ...
{
"artists" : {
"-KeZUDrJv555kteAcssL-" : {
"name" : "Atif Aslam",
"genre" : "Rock"
},
"-KeZUVXFIQdO7JiyRYk-" : {
"name" : "Arijit Singh",
"genre" : "Rock"
}
}
}
Database.database().reference().child("artists").childByAutoId().observeSingleEvent(of: .value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
print("\(String(describing: dictionary["name"] as? String))")
}
}, withCancel: nil)
Anyway, I do not know if it was clear, anything can comment before answering. Thank you
To display all artists in your database, load the artists node and loop over snapshot.children:
Database.database().reference().child("artists").observe(.value) { (snap:DataSnapshot) in
for child in snapshot.children {
print(child.key)
}
}
For this and more examples, I recommend reading the Firebase documentation, specifically the section on reading and writing lists.
I dont know if i understand your question correctly or what you are trying to do but maybe you can try
Database.database().reference().child("artists").observe(.value) { (snap:DataSnapshot) in
// This should print out your childIds
print(snap.key)
// This should print out the values after them
print(snap.value)
}
I have this piece of working code that saves data to Firebase:
let locRef = locationRef.childByAutoId()
let locItem = [
senderId : [
"location": getLocationID()
]
]
locRef.setValue(locItem)
And I want to retrieve the user's (identified by senderID) "location", so I tried this piece of code:
locationRef.child("location").child(senderId).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
self.locationId = snapshot.value!["location"] as! String
}) { (error) in
print(error.localizedDescription)
}
However my app is crashing when the piece of code is run, and there are no errors. I think my mistake may be that .child("location") must be something else, but I do not know what.
Database structure (JSON):
{
"locations" : {
"-KLEdoj2eiF7EW9m0815" : {
"W6vSOHZLTwNM33JYqkKHvaIVRF13" : {
"location" : "Seattle, WA"
}
},
"-KLLfcOvYHwIufBALM0-" : {
"W6vSOHZLTwNM33JYqkKHvaIVRF13" : {
"location" : "London, United Kingdom"
}
},
Any help would be appreciated thanks!
You should be referring to your location as the following
FIRDatabase.database().reference().child("locations").child(locationId).child(senderId).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
self.location = snapshot.value!["location"] as! String
}
For example:
If you have locationId = "-KLEdoj2eiF7EW9m0815" and senderId = "W6vSOHZLTwNM33JYqkKHvaIVRF13" the above call will set the self.location to "Seattle, WA"
I'm trying to make an app, where you have to choose a team name, and when the user enter his/hers team name, I want to check if the name already is in use.
teamNameTextField is a UITextField and for some reason no matter what I type in the text field, it prints "Team name is not in use". I don't know what I'm doing wrong here, can somebody help me?
My code:
rootRef.child("teams").queryOrderedByChild("teamName").queryEqualToValue(teamNameTextField.text).observeSingleEventOfType(.Value, withBlock: { (snap) in
if (snap.value is NSNull) {
print("Team name is not in use")
} else {
print("Team name is already in use")
}
})
my JSON data tree:
{
"teams" : {
"pbXvXYOKmJQqwSQZ9IlBykG7x1P2" : {
"teamName" : "Test111"
},
"owidUDkEnbCOsmNSoSFu2o2iu4y38RKJNF" : {
"teamName" : "Test222"
},
"pdnJCDmcdjsiHDFb8349HGD8372bfdhb" : {
"teamName" : "Test123"
}
}
}
My database rules:
{
"rules": {
".read": true,
".write": true
}
}
I realized the problem!
I tried to type print(teamNameTextField.text), and it printed: "Optional("Test111")"
So you have to put a ! after teamNameTextField.text, then it will only print "Test111"