0

I am using Firebase Database for my mobile and web application. I wanted to get advise for how to structure the JSON Tree. I have the following use case in mind:

Mobile app user logs in and gets all nearby restaurants in a list. User sets order on one restaurant. The restaurant owner uses web or mobile application to see incoming orders and accepts them. After accepting the order, the mobile app user gets response that his order has been accepted. Now my idea for the structure was the following:

enter image description here

SO we have one node at top level for each restaurant and each restaurant node contains a requests node which saves all the requests for this restaurants.

Is that structure ok or could this be structured better?

farahm
  • 1,326
  • 6
  • 32
  • 70
  • 1
    You've included a picture of the JSON tree in your question. Please replace that with the actual JSON as text, which you can easily get by clicking the Export button in your Firebase Database console. Having the JSON as text makes it searchable, allows us to easily use it to test with your actual data and use it in our answer and in general is just a Good Thing to do. – Frank van Puffelen Sep 11 '16 at 14:47
  • 1
    In NoSQL you often model the data for how your app uses it. For a good introduction, read this article on [NoSQL data modeling](https://highlyscalable.wordpress.com/2012/03/01/nosql-data-modeling-techniques/). – Frank van Puffelen Sep 11 '16 at 14:48

2 Answers2

3

Consider a data structure like this, you don't want to retrieve all the request when you get a restaurant and this way, you can get all the requests for a restaurant and all the requests from a particular user.

{
    "requests": {
        "req1": {
            "status": 0,
            "time": 1473593287,
            "user": { "u2": true }
        },
        "req2": {
            "status": 0,
            "time": 1473593227,
            "user": { "u1": true }
        },
        "req3": {
            "status": 0,
            "time": 1473594287,
            "user": { "u1": true }
        },
        "req4": {
            "status": 0,
            "time": 1473594227,
            "user": { "u2": true }
        },
    },
    "restaurant-requests": {
        "resA": {
            "req1": true,
            "req2": true
        },
        "resB": {
            "req3": true,
            "req4": true
        }
    },
    "restaurants": {
        "resA": {
            "name": "Example Restaurant A",
            "address": "1 Example Street"
        },
        "resB": {
            "name": "Example Restaurant B",
            "address": "2 Example Street"
        }
    },
    "user-requests": {
        "u1": {
            "req2": true,
            "req3": true
        },
        "u2": {
            "req1": true,
            "req4": true
        }
    },
    "users": {
        "u1": {
            "address": "123 Example Street"
        },
        "u2": {
            "address": "124 Example Street"
        },
    },
}
Callam
  • 11,409
  • 2
  • 34
  • 32
  • But this means that if there is a new request. I would have to add a node via android code to the `requests` node and an extra node to the `restaurant-requests\resX` node and an extra node to `user-requests\uX` node, right? Or is there a way that only one query would do all these changes through only one query? – farahm Sep 11 '16 at 11:54
  • Took me a while to wrap my head around the concept, but having these duplicates can save your user time – Callam Sep 11 '16 at 11:58
  • How will this save the user time? – farahm Sep 11 '16 at 11:58
  • 1
    Besides if you're worried about having to update both of these references, you can use multi-update locations to handle it in one quey – Callam Sep 11 '16 at 11:58
  • I mean request time – Callam Sep 11 '16 at 11:59
  • How will it save request time? This way I will have to call three times .setValue() which goes over the internet – farahm Sep 11 '16 at 12:00
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/123102/discussion-between-callam-and-faraz-ahmed-kamran). – Callam Sep 11 '16 at 12:01
  • In "req1": { "status": 0, "time": 1473593287, "user": { "u2": true }. Instead of directly writing the name of the user as value for the key `user`, why do you have an extra subnode with true as value instead? – farahm Sep 11 '16 at 12:28
  • 1
    Force of habit, I wrote a FIRDataObject class in swift that converts snapshots to objects and requires relationships to be in that format. – Callam Sep 11 '16 at 12:32
  • 1
    so the snapshot at `request/req1/user` gives `{"u2": true}` which can be converted to a User object with a key of `u2` but a value of just true. But now you have a user object with the key which you can request the full json of. – Callam Sep 11 '16 at 12:33
  • How would a query in android look like if I search for all queries of restaurant X? – farahm Sep 11 '16 at 13:48
  • 1
    You would want to observe /restaurant-requests/{restaurant-id}, this will give you all the request ids for a restaurant, which you can then cross reference at /requests/{request-id} to check request specific details like the user who sent the request etc. – Callam Sep 11 '16 at 14:56
  • OK, so now I have my reference: `rootNode.child("restaurant-requests").child("res-id");` and I have the `onDateChange` method to get all the requests of that restaurant where I get all these children: `dataSnapshot.getChildren()` and then I iterate over all of them and collect each key. And then I go to the `requests` node in the tree and ask for all requests corresponding to the keys I have selected prior. Is that the right approac? – farahm Sep 12 '16 at 13:48
  • Could you please help? – farahm Sep 13 '16 at 07:30
  • You need to iterate through each child snapshot of the `restaurant-requests` ref and for each snapshot, you will make a one time observation on the value `requests/{child snapshot key}` ref. So this means you'll have to make a request per `restaurant-request` – Callam Sep 13 '16 at 08:20
  • One request per each restaurant-request of that particual restauant. Isnt that heavy on the connection traffic? – farahm Sep 13 '16 at 08:35
  • Yes but you could just enable persistance – Callam Sep 13 '16 at 09:36
  • OK, I am retrieving the keys of all the restaurants requests with `String key = iterator.next().getKey()` and then I try to retrieve the details of that request with: `DatabaseReference currRequest = rootNode.child("requests/" + key)` but I do not know how to get the detail values out of `currRequest`. I mean I cant find `getValue()` as it is available on `DataSnapshot` – farahm Sep 13 '16 at 11:02
  • Hey Callam, I have opened a new question for the problem I have: http://stackoverflow.com/questions/39477847/android-firebase-wait-for-data – farahm Sep 13 '16 at 19:45
1

enter image description here

That's what I would do.. good luck!

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Nirel
  • 1,855
  • 1
  • 15
  • 26