Bo Jackson
Bo Jackson

Reputation: 357

Wrong snapshot return on firebase query

So I have an app that uses firebase. In this app, I want to grab events whose end time is greater than or equal to the current day. I made this function that I believe accomplishes that. However, it returns nothing

static func show(forEventKey eventKey: String, completion: @escaping (Event?) -> Void) {
    print(eventKey)
    let ref = Database.database().reference().child("events").child(eventKey)

    ref.queryOrdered(byChild: "end")
        .queryStarting(atValue: Date().timeIntervalSince1970, childKey: "end")
        .observeSingleEvent(of: .value, with: { (snapshot) in

            print(snapshot)

            guard let event = Event(snapshot: snapshot) else {
                return completion(nil)
            }

            completion(event)

        })
}

A child in my tree under the events node looks like this

"BEVT" : {
  "attend:count" : 5,
  "event:category" : "Seize The Night",
  "event:city" : "Philadelphia",
  "event:date" : {
    "end:date" : "06/18/2018",
    "end:time" : "7:01 PM",
    "start:date" : "06/17/2018",
    "start:time" : "12:01 PM"
  },
  "event:datetime" : {
    "end" : 1529362860,
    "start" : 1529251260
  },
  "event:description" : "Travis Scott is ready to hit the road. The 24-year-old hitmaker will embark on his Birds Eye View tour, powered by Live Nation, in support of his sophomore album and Billboard 200 No. 1 Birds in the Trap Sing McKnight.",
  "event:imageURL" : "https://firebasestorage.googleapis.com/v0/b/eventful-3d558.appspot.com/o/event_flyers%2FtravisScott-compressor.png?alt=media&token=c6e46da1-1395-4a37-a8fc-3ff53d5c0d4d",
  "event:name" : "birds eye view tour",
  "event:promo" : "https://firebasestorage.googleapis.com/v0/b/eventful-3d558.appspot.com/o/event_promo_vid%2FBEVT%2FTravis%20Scott_%20Houston%20Birds%20Eye%20View%20Tour%20Promo.mp4?alt=media&token=6d27d76e-281e-4083-a0ff-dbe2f25703e7",
  "event:state" : "PA",
  "event:street:address" : "5748 Baltimore Pike",
  "event:zip" : 19143
}

When I print the snapshot it looks like this which shows me that it found it but it doesn't return the entire snapshot

Snap (BEVT) {
    "event:datetime" =     {
        end = 1529445600;
        start = 1529442000;
    };
}

Can anyone see where my query went wrong because I am kinda confused?

I am grabbing the keys using geofire being that my app is location based. Upon grabbing those keys I pull relevant info. I am positive that I can't change how geofire stores things. So im left with grabbing the key and just returning the snapshot and creating the event object based off of the current date. So basically if event end date is later then today return it. If not don't

I have this eventsbylocation node which grabs the keys based off of location using geofire. Let's say I am near BEVT which is in an event key, geoFire would grab that key. Now that events location node doesn't hold dates. After getting the key through geofire I query the events node based solely off of the keys I receive from geofire. How woulf I query based off of this collection of keys and only return the ones with after a certain date based off of that timestamo.

"eventsbylocation" : {
    "ABP" : {
      ".priority" : "dr4e3nzh0q",
      "g" : "dr4e3nzh0q",
      "l" : [ 39.9840919, -75.1808035 ]
    },
    "BEVT" : {
      ".priority" : "dr4e0r56u7",
      "g" : "dr4e0r56u7",
      "l" : [ 39.9412882, -75.21873459999999 ]
    }

This is the function that grabs the keys via geoFire

 static func showEvent(for currentLocation: CLLocation,completion: @escaping ([Event]) -> Void) {
        //getting firebase root directory
        var keys = [String]()
        var currentEvents = [Event]()
        var geoFireRef: DatabaseReference?
        var geoFire:GeoFire?
        geoFireRef = Database.database().reference().child("eventsbylocation")
        geoFire = GeoFire(firebaseRef: geoFireRef!)
        let circleQuery = geoFire?.query(at: currentLocation, withRadius: 17.0)
        circleQuery?.observe(.keyEntered, with: { (key: String!, location: CLLocation!) in
            print("Key '\(key)' entered the search area and is at location '\(location)'")
            if let currentKey = key {
                keys.append(currentKey)
            }
        })

        circleQuery?.observeReady({
            let dispatchGroup = DispatchGroup()
            for key in keys {
                dispatchGroup.enter()
                EventService.show(forEventKey: key, completion: { (event) in
                    if let currentEvent = event {
                        currentEvents.append(currentEvent)
                    }
                    dispatchGroup.leave()
                })
            }

            dispatchGroup.notify(queue: .main, execute: {
                print(currentEvents.count)
                completion(currentEvents)
            })

        })

    }

Upvotes: 0

Views: 393

Answers (2)

Jay
Jay

Reputation: 35657

We can't see enough of the events node to know for sure but lets assume a very simple events structure which may match yours. If not, let me know and I will update.

events
   event_0 // BEVT in your structure?
      attend_count: 3
      event_datetime
         end: 5
         start: 3
   event_1
      attend_count: 7
      event_datetime
         end: 6
         start: 2
   event_2
      attend_count: 9
      event_datetime
         end: 5
         start: 1

We are going to leverage a Firebase Deep Query or Deep Path Query to retrieve the nodes you want.

Suppose we want all events that end at 5, here's the code to dig into a deep path and retrieve event_0 and event_2

let eventsRef = self.ref.child("events")
let eventQuery = eventsRef.queryOrdered(byChild: "event_datetime/end").queryEqual(toValue: 5)
eventQuery.observeSingleEvent(of: .value, with: { snapshot in
    for child in snapshot.children {
        let snap = child as! DataSnapshot
        let dict = snap.value as! [String: Any]
        let attendCount = dict["attend_count"] as! Int
        let eventDateTimeSnap = snap.childSnapshot(forPath: "event_datetime")
        let eventDateTimeDict = eventDateTimeSnap.value as! [String: Any]
        let end = eventDateTimeDict["end"] as! Int
        let start = eventDateTimeDict["start"] as! Int
        print("event: \(snap.key)  attending: \(attendCount)  start: \(start)  end:\(end)")
    }
})

and the output

event: event_0 attending: 3  start: 3  end:5
event: event_2 attending: 9  start: 1  end:5

With this example we are getting events ending at 5. You could easily expand the query to get events that end between 1 and 5 or events that are after today (via a timestamp such as 20180619) etc.

Upvotes: 0

Govind Kumawat
Govind Kumawat

Reputation: 1592

Your code is trying to be too specific and you are telling it to look at a particular end for the data in the query - which doesn't make sense as if you know the exact path, you wouldn't need to query!

This is a common misunderstanding - just remember that queries need to be provided the parent node and then the child node of what you are querying for as it will then iterate over the child_nodes just underneath the parent.

parent_node
  child_node
     child_node_of_what_you_are_querying
  child_node
     child_node_of_what_you_are_querying

so your query should be look like this.

 let ref = Database.database().reference().child("events").child("event_Key")

 ref.queryOrdered(byChild: "end")
    .queryStarting(atValue: Date().timeIntervalSince1970)
    .observeSingleEvent(of: .value, with: { (snapshot) in

     print(snapshot)

    })

Upvotes: 0

Related Questions