1

How can I make a query to get all bookings of all users that have timestamp in the range of 1519912278 ...1520689878 ? In Firebase docs it states that I can query deeply nested children.

According to this answer, it should work https://stackoverflow.com/a/47805607 , but it return null.

What is the flow of my User app? :
1. User singn up
2. When booking is made, it is saved at /Users/UID/stripe_customer_created_with_card/bookingNumber{booking object}

Why do I need all bookings located under /Users?:
There is a second app designed for Workers which can observe /Users node and each worker should be able to get bookings from /Users based on a timeStamp. For example a worker1382 can read bookings made by /Users from 16 March 2018 to 24 March 2018.

dbRef = FIRDatabase.database().reference().child("Users")
dbRef.queryOrdered(byChild: "TimeStampDateAndTime")
     .queryStarting(atValue: "1519912278")
     .queryEnding(atValue: "1520689878")
     .observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in         
        print(snapshot.value) //returns null
     }

 Users
   UID
    cus_CRC50bSq7rXuHv         //stripe customer id for the user
       617643762                //booking number
         TimeStampDateAndTime: "1521309610"
         Postcode: "E14 9DS"
         BookingNumber:"617643762"

Another question: The parent key of the booking object is equal to BookingNumber. If I replace the parent key 617643762 with TimeStampDateAndTime value 1521309610, would I be able to order the bookings by time stamp and ultimately get only the ones that are within a certain range 1519912278 ...1520689878? So, the path would look like Users/UID/cus/1521309610: {object goes here}

From Firebase Documentation

Queries can also be ordered by deeply nested children, rather than only children one level down. This is useful if you have deeply nested data like this:

{
  "lambeosaurus": {
    "dimensions": {
      "height" : 2.1,
      "length" : 12.5,
       "weight": 5000
     }
   },
}

To query the height now, we use the full path to the object rather than a single key. Now, my question is, what can't I do if I don't know the full path?

 let ref = Firebase(url:"https://dinosaur-facts.firebaseio.com/dinosaurs")
 ref.queryOrderedByChild("dimensions/height").observeEventType(.ChildAdded, withBlock: { snapshot in
 if let height = snapshot.value["height"] as? Double {
     println("\(snapshot.key) was \(height) meters tall")
   }
})

EDIT 2

Initial Structure looks like this:

 {
 "Users" : {
    "I50dHN7wPqPJClPfYDG76gXizdD2" : { //-> user?.uid of a logged in user 
       "cus_CRC50bSq7rXuHv" : {
         "617643762" : {
             "TimeStampDateAndTime" : "1521309610"
          }
        }
     }
   }
 }

Modified structure:

{
 "Users" : {
   "I50dHN7wPqPJClPfYDG76gXizdD2" : {
       "1521309610" : { // -> store timeStamp as the immediate child key of UID rather than the booking number
         "TimeStampDateAndTime" : "1521309610",
          "BookingNumber": "617643762"
      }
    }
  }
}


 {
   "UsersProfile":{
     "I50dHN7wPqPJClPfYDG76gXizdD2":{
        "StripeCustomer":"cus_CRC50bSq7rXuHv", // -> store StripeCustomer on the UsersProfile
        "Name": "John Doe"
      }
   }
}
bibscy
  • 2,598
  • 4
  • 34
  • 82
  • Well, you are defining ref and then observing on finalRef. Also, your data structure is one level too deep for this query - if TimeStampDateAndTime was a child of the *bookings* node it would work. – Jay Mar 15 '18 at 20:05
  • While the ref and finalRef issue has been corrected, the problem still exists in that your firebase structure is too deep for that query. You will need to either create a different node to use that query with or re-structure your current structure to support that query. Firebase supports deep queries but the database has to be structured correctly for that to work. See [this question](https://stackoverflow.com/questions/45547102/how-to-get-childs-whose-arrays-contain-a-certain-value/45552776#45552776) for an example structure and a query that supports it. – Jay Mar 16 '18 at 13:01
  • What are the `Users` keys? I mean firebase query works with auto generated keys. – TheTiger Mar 16 '18 at 13:02
  • Oh and see [Deep Query](https://stackoverflow.com/questions/35514497/firebase-in-swift-nested-query-not-working-properly/35516581#35516581) for another question and answer that should help. On that one, review @frankvanpuffelen answer but then check out the structure and query in my follow up answer. It's ObjC but the structure is in the format that works for deep queries. – Jay Mar 16 '18 at 13:05
  • @TheTiger UID == FIRUser?.uid – bibscy Mar 16 '18 at 13:20
  • @bibscy No they should be auto generated while making any reference use `childByAutoId()`. – TheTiger Mar 16 '18 at 13:23
  • And BTW Use `FireStore` if you need deep queries. – TheTiger Mar 16 '18 at 13:26
  • @TheTiger. Once a user is logged in, how would I retrieve any bookings if UID is not a child of Users? I mean, I need some means to find data belonging to a User. Could you write a more comprehensive solution in the Answer area. FireStore is still in Beta, my project is almost finished, so switching to another database type is not really feasible at this stage. – bibscy Mar 16 '18 at 13:51
  • @Jay thanks for your advice. I am thinking about restructuring the database like this: 1st path. create `/Profile/UID: {stripeCustomer: "cus_CRC50bSq7rXuHv", name: "John Doe"}` 2nd path. create `/Users/UID/timeStamp:{booking Object}`. Would I be able to perform a query on 2nd path in order to get only the bookings within a certain time stamp range? If so, how can I do it? – bibscy Mar 16 '18 at 15:00

1 Answers1

3

You can query properties at a known path under each child node. So you can query dimensions/weight in the dinosaur sample, and you can query 617643762/TimeStampDateAndTime from your data.

But you can't query */TimeStampDateAndTime, since that's not a known path.

If you need to get a list of bookings in a date range across all users, you will need to modify your data structure to allow that query. For example, by adding a top-level list of bookings:

"Bookings": {
    "book_617643762"
        Customer: "cus_CRC50bSq7rXuHv"
        TimeStampDateAndTime: "1521309610"
        Postcode: "E14 9DS"
}

With this additional structure, you can then query:

dbRef = FIRDatabase.database().reference().child("Bookings")
dbRef.queryOrdered(byChild: "TimeStampDateAndTime")
     .queryStarting(atValue: "1519912278")
     .queryEnding(atValue: "1520689878")
     .observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in         
        print(snapshot.value) //returns null
     }
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • If I had the structure like this `/Users/UID/timeStamp:{booking Object}` would I be able to get the bookings that have the child node timeStamp within a time stamp range ? I wrote in my last comment in my original question a more elaborate explanation. Thank you. – bibscy Mar 16 '18 at 15:07
  • That depends on what `{booking Object}` looks like. The rules are simple: the property you want to order/filter on must be at a fixed path under each child. If it is, you can order/filter on it. If it is not on a fixed path, you can't order/filter on it. – Frank van Puffelen Mar 16 '18 at 17:28
  • The bookingObject would look like `/Users/UID/timeStamp: {Customer: "cus_CRC50bSq7rXuHv", TimeStampDateAndTime: "1521309610", Postcode: "E14 9DS"}` – bibscy Mar 16 '18 at 20:08
  • It looks like `FIRDatabase.database().reference("Users").queryOrdered(byChild: "timeStamp/TimeStampDateAndTime").queryStarting(atValue: "1519912278").queryEnding(atValue: "1520689878")` should work there. If not, edit your question to include the exact JSON (which you can export as text from your Database console) and code you use and we can have a look. – Frank van Puffelen Mar 16 '18 at 20:47
  • Please see EDIT 2 in my original question. In this path `FIRDatabase.database().reference("Users").queryOrdered(byChild: "timeStamp/TimeStampDateAndTime")` , timeStamp is not the name of the child, but a variable time stamp of type `Int`, like 1521309610 – bibscy Mar 16 '18 at 22:10
  • That value is still not at a fixed path (the `1521309610` key is dynamic), so can't be queried. Also see https://stackoverflow.com/questions/27207059/firebase-query-double-nested – Frank van Puffelen Mar 16 '18 at 22:50
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167002/discussion-between-bibscy-and-frank-van-puffelen). – bibscy Mar 17 '18 at 00:03