Chris_1983_Norway
Chris_1983_Norway

Reputation: 399

How to query firebase to filter on a certain value

Im trying to get all the imageURLs for all activities that are for a specific user (UserId). the content of the snapshot include the correct entries, however the imageURL is not appended to imageArray. What am I doing wrong?

 // Get all images for a specific user

    func getImagesForUser(userId:String, handler: @escaping (_ imageArray: [String]) -> ()) {
        var imageArray = [String]()

        REF_ACTIVITY.queryOrdered(byChild: "userId").queryEqual(toValue: userId).observe(.value, with:  { snapshot in
            dump(snapshot)
            guard let data = snapshot.value as? NSDictionary else { print("else was returned"); return }

            let imageURL = data["imageURL"] as? String ?? ""
            imageArray.append(imageURL)
            handler(imageArray)
        })

    }

Output from dump(snap)

Snap (-L2RDXTKANzD8YGpPl92) {
    gearId = asfasfsf;
    imageCount = 3;
    imageURLs =     {
        1 = "http://www.foo.com";
        2 = "http://www.foo2.com";
        3 = "http://www.foo3.com";
    };
    killCount = 10;
    kills = 12;
    likeCount = 2;
    likes =     {
        fas86q39rasf = 1;
    };
    userId = NhZZGwJQCGe2OGaNTwGvpPuQKNA2;
}

Snap (-L2RDXTKANzD8YGpPl92) {
    gearId = asfasfsf;
    imageCount = 3;
    imageURLs =     {
        1 = "http://www.foo.com";
        2 = "http://www.foo2.com";
        3 = "http://www.foo3.com";
    };
    killCount = 10;
    kills = 12;
    likeCount = 2;
    likes =     {
        fas86q39rasf = 1;
    };
    userId = NhZZGwJQCGe2OGaNTwGvpPuQKNA2;
}

Update - output of Dict

24 elements
  ▿ 0 : 2 elements
    - key : "commentCount"
    - value : 1
// removed some info
...
  ▿ 12 : 2 elements
    - key : "imageURLs"
    ▿ value : 4 elements
      - 0 : <null>
      - 1 : https://firebasestorage.googleapis.com/v0/b/shoota-179610.appspot.com/o/activity_image%2FCA6F4C93-8F5F-456C-9FD6-F2EACC444739?alt=media&token=522d957b-dedf-4bdc-9cbc-1de581284393
      - 2 : https://firebasestorage.googleapis.com/v0/b/shoota-179610.appspot.com/o/activity_image%2FCA6F4C93-8F5F-456C-9FD6-F2EACC444739?alt=media&token=522d957b-dedf-4bdc-9cbc-1de581284393
      - 3 : https://firebasestorage.googleapis.com/v0/b/shoota-179610.appspot.com/o/activity_image%2FCA6F4C93-8F5F-456C-9FD6-F2EACC444739?alt=media&token=522d957b-dedf-4bdc-9cbc-1de581284393
  ▿ 13 : 2 elements
    - key : "imageURL"
    - value : https://firebasestorage.googleapis.com/v0/b/shoota-179610.appspot.com/o/activity_image%2FCA6F4C93-8F5F-456C-9FD6-F2EACC444739?alt=media&token=522d957b-dedf-4bdc-9cbc-1de581284393
  ▿ 14 : 2 elements
    - key : "killCount"
    - value : 10

Upvotes: 0

Views: 545

Answers (1)

Jay
Jay

Reputation: 35648

There are a few issues with the code in the question:

It appears you just want to get the data one time but that observe will stay attached and any time there's a change anywhere in that node that matches the query, you will be notified. If you just want it one time, use observeSingleEvent instead

Also, you are returning multiple nodes with that query - and those will need to be worked with one at a time via a loop to iterate over the returned data.

Here's a very simplified example of that technique. Note there is no error checking; for example if one of the returned nodes doesn't contain an imageURL key that should be handled with a guard or perhaps a nil-coalescing operator (??) to assign a default in that case.

let activitesRef = self.ref.child("activities")
let query = activitesRef.queryOrdered(byChild: "userId").queryEqual(toValue: userId)
query.observeSingleEvent(of: .value, with: { snapshot in
    for child in snapshot.children {
        let snap = child as! DataSnapshot
        let dict = snap.value as! [String: Any]
        let url = dict["imageURL"] as? String ?? "no url"
        print(url)
    }
})

Edit:

This code assumes a structure like this

activities
  activity_0
     userId: "uid_0"
     imageURL: "www.someurl.com"
  activity_1
     userId: "uid_1"
     imageURL: "www.anotherurl.com"
  activity_2
     userId: "uid_0"
     imageURL: "www.coolurl.com"

in the above case two nodes will be returned in the snapshot and the above code will iterate over those nodes and print the url from each.

www.someurl.com
www.coolurl.com

Another Edit:

Based on some follow up comments, it appears there are multiple urls for each user. Here's an updated Firebase structure to match:

activities
  activity_0
     userId: "uid_1"
     urls
       url_0: "www.someurl.com"
       url_1: "www.anotherurl.com"
       url_2: "www.coolurl.com"
  activity_1
     userId: "uid_1"
     urls
       url_0: "www.thisurl.com"
       url_1: "www.thaturl.com"
       url_2: "www.ou812url.com"

Note that arrays should be avoided in NoSQL databases so we're using url_0, url_1 but in reality those node keys should be created with childByAutoId.

And then the code to query for all nodes for uid_1 and print their url's

let activitesRef = self.ref.child("activities")
let query = activitesRef.queryOrdered(byChild: "userId").queryEqual(toValue: userId)
query.observeSingleEvent(of: .value, with: { snapshot in
    for child in snapshot.children {
        let snap = child as! DataSnapshot
        print(snap.key)
        let urlSnap = snap.childSnapshot(forPath: "urls")
        for url in urlSnap.children {
            let aUrlSnap = url as! DataSnapshot
            let key = aUrlSnap.key
            let val = aUrlSnap.value as! String
            print("  key: \(key)  url: \(val)")
        }
    }
})

and finally the output

activity_0
  key: url_0  url: www.someurl.com
  key: url_1  url: www.anotherurl.com
  key: url_2  url: www.coolurl.com
activity_1
  key: url_0  url: www.thisurl.com
  key: url_1  url: www.thaturl.com
  key: url_2  url: www.ou812url.com

Upvotes: 1

Related Questions