如何在Firebase JSON树中表示双向关系?

mm2*_*m24 7 json nosql database-normalization firebase firebase-realtime-database

警告:

  • 这是一个练习,以了解Firebase中更好的JSON数据库设计
  • 这不一定是现实的

我在用户和门钥匙之间有两种关系.我想了解:

  • 如何直观地表示这种关系(我可以想象它只是作为两个独立的树)
  • 如何在Firebase上运行,用户门钥匙都是父节点"myparentnodename"的子节点吗?
  • 如果我以这种方式对数据库建模,感觉效率非常低,因为每次我查询子节点"用户"时,我都会得到所有用户的回复.还是我错了?是否可以仅返回与特定用户匹配的数据?例如,让用户在哪里"user = user1"?我们可以做嵌套查询吗?例如,将前一个条件与门钥匙上的某些条件相结合,以便返回的JSON对象仅与"user1"节点中包含的门钥匙相关?

在此输入图像描述

Jay*_*Jay 11

这是一个很长的答案,因为你的问题实际上是关于5个不同的问题.

根节点是:myparentnodename

您的用户

  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
Run Code Online (Sandbox Code Playgroud)

和你的钥匙

  keys
    key_0
      uid_0: true
    key_3
      uid_0: true
      uid_2: true
    key_5
      uid_5: true
Run Code Online (Sandbox Code Playgroud)

通过这种结构,所有元素都"指向"彼此.

如果您查询uid_0,您可以看到他们使用键0和3

如果查询key_3,则可以看到它们属于用户0和2

你的问题是

每次我查询子节点"用户"时,我都会让所有用户都回来

那稍微不完整了.查询完成后,通常会查询特定的内容.但是,使用Firebase,有两种方法可以检索数据:观察节点和查询.

如果要返回用户节点中的所有用户,您将通过.Value(或.ChildAdded一次1)观察该节点.

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
    }
})
Run Code Online (Sandbox Code Playgroud)

请注意,上面将观察者附加到用户节点,因此该节点中的任何未来更改都将通知应用程序并将整个节点重新发送到应用程序

如果您只想要一个用户的信息,并且不想继续观看更改

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
})
Run Code Online (Sandbox Code Playgroud)

最后,查询属于uid_0的所有密钥(在这个例子中有点多余,因为我们已经从他们的节点知道了哪些密钥).如果钥匙ref还包含其他信息,例如门名,门所在的建筑物或门位置,那么它将更合适并且需要不同的结构,因此假设情况如此:

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
})
Run Code Online (Sandbox Code Playgroud)

请注意,此代码是Swift,因为问题中未指定平台.

另一个问题:

我们可以做嵌套查询吗?例如,将前一个条件与门钥匙上的某些条件相结合,以便返回的JSON对象仅与"user1"节点中包含的门钥匙相关?

我认为你的意思是你可以查询uid_2,看看他们有哪些密钥,然后加载这些特定密钥的信息.

是! 但是......(总有一个但是)

Firebase是异步的,因此在嵌套查询时必须考虑到这一点,即您需要确保在获取更多数据之前返回所有数据.因此,例如,如果您想要uid_2密钥数据,则可以在节点uid_2上观察单个事件.然后你可以拥有他们的密钥,然后可以在每个密钥上观察SingleEventOfType.

从技术上讲,这可以工作,但异步数据飞来飞去,你可能最终会在其他代码上踩踏代码并在实际返回之前处理数据.

更好的选择(根据我的例子)是完全避免这种情况,并查询关键节点的uid_2密钥.

作为旁注,观察节点的开销要比查询少得多,因此如果要加载单个节点并且知道路径,请使用observe.