How to represent a two ways relationship in a Firebase JSON tree?

痞子三分冷 提交于 2019-12-03 00:24:34

This is a very long answer as your question was actually about 5 different questions.

root node is: myparentnodename

Your users

  users
    uid_0
      name: "William"
      door_keys:
        key_0: true
        key_3: true
    uid_2
      name: "Leonard"
      door_keys:
        key_3: true
        key_5: true

and your keys

  keys
    key_0
      uid_0: true
    key_3
      uid_0: true
      uid_2: true
    key_5
      uid_5: true

With this structure, all of the elements 'point' at each other.

If you query uid_0 you can see that they use keys 0 and 3

If you query key_3 you can see they belong to users 0 and 2

Your question was

every time I would query the child node "users" I would get all the users back

That's slightly incomplete. When a query is done, you usually query for something specific. With Firebase however, there are two ways to retrieve data: observing a node and a query.

If you want back all users in the users node you would observe that node by .Value (or .ChildAdded for 1 at a time).

ref = myParentNodeName
let usersRef = myParentNodeName.childByAppendingPath("users")

usersRef.observeEventType(.Value, withBlock: { snapshot in

    //.Value can return multiple nodes within the snapshot so iterate over them
    for child in snapshot.children {
        let name = child.value.objectForKey("name") as! String
        print(name) //prints each users name
    }
})

note that the above attaches an observer to the users node so any future changes within that node will notify the app and re-send the entire node to the app

If you want just one user's info, and don't want to continue watching for changes

ref = myParentNodeName
let usersRef = myParentNodeName.childByAppendingPath("users")
let thisUserRef = usersRef.childByAppendingPath("uid_2")
thisUserRef.observeSingleEventOfType(.Value, withBlock: { snapshot in

    let name = child.value.objectForKey("name") as! String
    print(name) //prints each users name
})

Finally, to query for all keys that belong to uid_0 (which is a little redundant in this example since we already know which keys they have from their node). If the keys ref also contained other info like the door name, the building the door was in, or the door location, it would be more appropriate and would require a different structure, so assume that's the case:

ref = myParentNodeName
let keysRef = myParentNodeName.childByAppendingPath("keys")

keysRef.queryOrderedByChild("uid_0").queryEqualToValue(true)
  .observeSingleEventOfType(.Value, withBlock: { snapshot in

        let doorLocation = child.value.objectForKey("door_location") as! String
        print(doorLocation) //prints each users name
})

note this code is Swift since the platform was not specified in the question.

The other question:

Can we do nested queries? e.g. combine the previous condition with some condition on the door keys so the JSON object returned is only relevant to the door-keys contained in the "user1" node?

I think you mean can you query for uid_2, see which keys they have and then load in the info from those specific keys.

Yes! But... (there's always a but)

Firebase is asynchronous so you have to take that into account when nesting queries i.e. you need to ensure all of the data is returned before getting more data. So for example, if you wanted uid_2 key data, you could observeSingleEventOfType on node uid_2. You would then have their keys and could then observeSingleEventOfType on each key.

Technically this will work but with asynchronous data flying around, you could end up with code stomping on other code and processing data before it's actually been returned.

The better option (per my example) is to just avoid that entirely and query the keys node for uid_2's keys.

As a side note, observing a node has a lot less overhead than a query so if you want to load a single node and you know the path, use observe.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!