Copernicus
Copernicus

Reputation: 100

Firebase Query using Swift not working as expected

I'm trying to query my Firebase database to find users of a particular name or email. I've found several examples of how to do this, all of them have seemed relatively easy to follow, but none have worked as expected for me.

Here is an example of how my json data is structured.

{
 "allUsers" : {
    "uid0001" : {                        
       "userInfo" : {
          "email" : "[email protected]",                  
          "firstName" : "firstName1",
          "lastName" : "lastName1",          
          "uid" : "uid0001"
          }
       },
    "uid0002" : {        
       "userInfo" : {
          "email" : "[email protected]",
          "firstName" : "firstName2",
          "lastName" : "lastName2",          
          "uid" : "uid0002"
          }
       }
    }    
}

And here is a sample function of how I'm trying to query the database

func performQuery(forName queryText:String)
{
    let key = "firstName"

    let ref1 = firebaseDatabaseManager.allUsersRef.queryOrdered(byChild: queryText)
    let ref2 = firebaseDatabaseManager.allUsersRef.queryEqual(toValue: queryText, childKey: key)

        //ref.observeSingleEvent(of: .childAdded, with: {(snapshot) in
        ref1.observe(.childAdded, with: {(snapshot) in

            let userId = snapshot.key

            if let dictionary = snapshot.value as? [String: AnyObject]
            {
                if let userInfo = dictionary["userInfo"] as? [String:AnyObject]
                {
                    if
                        let email           = userInfo["email"]         as? String,
                        let firstName       = userInfo["firstName"]     as? String,
                        let lastName        = userInfo["lastName"]      as? String
                    {
                        let user = User.init(withFirst: firstName, last: lastName, userEmail: email, uid: userId)
                    }
                }
            }
        })
}

You can see here I have two examples of how I'm structuring ref and two examples of how I'm observing the reference, although I've tried every possible combination that I can think of.

If I'm using ref.observe(.... The block will execute for all users at the node regardless of if queryText is actually present or not. If I'm using ref.observeSingleEvent(of:.... The block will execute for the topmost user in the json structure.

On top of that, I've tried several variations of reference that return nothing at all.

Any help at all is appreciated! Thanks

Upvotes: 1

Views: 703

Answers (3)

Jay
Jay

Reputation: 35677

This issue is the Firebase structure is (unnecessarily) too deep.

What you have is

"allUsers" : {
    "uid0001" : {                        
       "userInfo" : {    <- This is the issue
          "email" : "[email protected]",                  
          "firstName" : "firstName1",
          "lastName" : "lastName1",          
          "uid" : "uid0001"
          }
       },

It should (could) be

"allUsers" : {
    "uid0001" : {                        
        "email" : "[email protected]",                  
        "firstName" : "firstName1",
        "lastName" : "lastName1"
    }
}

There's probably no need to have the userInfo node inside the uid0001 node.

Also, you probably don't need the uid stored in the node as well as using it as the key - when the node is returned you can always get the uid from the snapshot.key for each user.

That being said, you can actually do this with a deep query, but it doesn't appear to be needed in this case. (See Frank's answer as it is the correct solution for the structure posted in the question)

and to query for a specific first name using the structure I suggested

let fName = "firstName1"
let queryAllUsersRef = allUsersRef.queryOrdered(byChild: "firstName")
                                  .queryEqual(toValue: fName)

//get all of the users with firstName1
queryRef.observeSingleEvent(of: .value, with: { snapshot in

      //snapshot may return more than one user with that first name
      //  so iterate over the results
      for snap in snapshot.children {
           let userSnap = snap as! FIRDataSnapshot //each user is it's own snapshot
           let userKey = commentSnap.key //the uid key of each user
           let userDict = userSnap.value as! [String:AnyObject] 
           let email = userDict["email"] as! String
           print("uid: \(userKey) has email: \(email)"
      }
   })

Upvotes: 0

Frank van Puffelen
Frank van Puffelen

Reputation: 600131

You need to combine queryOrderedByChild: and queryEqualToValue: to get the correct results:

let query = firebaseDatabaseManager.allUsersRef
    .queryOrdered(byChild: "userInfo/" + key)
    .queryEqual(toValue: queryText)

query.observe(.childAdded, ...

Upvotes: 1

anho
anho

Reputation: 1735

Try replacing

let ref2 = firebaseDatabaseManager.allUsersRef.queryEqual(toValue: queryText, childKey: key)

with

let ref2 = ref1.queryEqual(toValue: queryText)

and then call:

ref2.observe(.childAdded, with: {(snapshot) in

Since right now you are not looking for a certain user but for all users

Upvotes: 0

Related Questions