2017-07-08 54 views
0

我非常熟悉的“child_added”,“child_changed”,“child_removed”和“价值”的理念。 每当我使用一个列表,这应该是动态更新自己,我应该使用除“值”之外的所有函数,并且每当我只需要数据的静态快照时,我将使用“值”。如何有效地使用child_added

我的问题如下:

难道真的写三个触发器(4如果算上“child_moved”),每当我有一个列表的最好方法?一个简单的应用程序有很多列表。 如果是的话,它是如何以最有效的方式在JavaScript中完成的?我目前的做法如下:

  • on child_added:遍历整个列表;看看密钥与我刚从事件收到的密钥相等的位置,并将其值保存为oldValue;现在发现prevChildKey指数和prevChildKey的索引后插入刚接到孩子,而除去myList中[myList.indexOf(属性oldValue)]从列表中
  • 上child_changed:遍历我的整个列表;看看密钥与我刚从事件收到的密钥相等的位置,并将其值保存为oldValue;设置myList [myList.indexOf(oldValue)] = newValue;
  • on child_removed:与上面相同,只是与myList.splice(...)
  • on child_moved:我没有实现这一点。但是我可能需要它,当调用child_changed时,这导致我的元素的顺序发生变化。所以有一个非常类似的逻辑child_added

有没有办法以更优雅的方式处理这个问题?我第一次尝试通过myList [child.key]访问元素,但这不适用于我。

编辑:添加代码来说明吧,很多的代码申请每个列表在我的应用

myRef.orderByChild("timestamp").on("child_added",(message,prevChildKey) => { 
     //Transform the firebase-date into my own format 
     var template = { 
      senderName: message.val().sender, 
      time: message.val().timestamp, 
      id: message.key} 

     //Check where to add this 
     if(prevChildKey){ 
      this.messages.forEach(currentMessage => { 
       if(currentMessage.id === prevChildKey){ 
        var indexToAdd = this.messages.indexOf(currentMessage); 
        this.messages.splice(indexToAdd+1,0,template]; 
       } 
      }); 
     }else 
      this.messages.unshift(template); 

}); 
myRef.on("child_changed", message => { //orderByChild makes no sense here, right ? 
    //Transform the firebase-date into my own format 
    var template = { 
     senderName: message.val().sender, 
     time: message.val().timestamp, 
     id: message.key} 

    var toBeUpdated = undefined; 
    this.messages.forEach(currentMessage => { 
     if(currentMessage.id === message.id){ 
      this.messages[this.messages.indexOf(currentMessage)] = template; 
     } 
    }) 

    //How do I preserve ordering here, since I was ordering by timestamp on child_added before and I don't check if that value changed 
} 
myRef.on("child_removed", oldMessage => { 

    //Remove the message 
    this.messages.forEach(currentMessage => { 
     if(currentMessage.id === oldMessage.id){ 
      this.messages.splice(this.messages.indexOf(currentMessage),1); 
     } 
    }) 
} 
myRef.orderByChild("timestamp").on("child_moved", (message,prevChildKey) => { //Not too sure, how this works. Do I need the orderByChild here to preserve it ? 

    var messageToMove = undefined; 
    var messagePosition = undefined; 
    var indexToMoveTo = undefined; 
    this.messages.forEach(currentMessage => { 
     if(currentMessage.id === message.id){ 
      messagePosition = this.messages.indexOf(currentMessage); 
      messageToMove = this.messages[messagePosition]; 
     } 
     if(currentMessage.id === prevChildKey){ 
      indexToMoveTo = this.messages.indexOf(currentMessage) + 1; 
     } 
    }) 

    //Remove the message from where it was 
    this.messaged.splice(messagePosition,1); 
    //Add the message at the new position 
    this.messages.splice(indexToMoveTo,0,messageToMove); 

} 
+0

您在问我们是否有更有效的方法来做某件事。我们大多数人都不擅长解析代码的描述。所以请发布[演示您当前解决方案的最小实际代码](http://stackoverflow.com/help/mcve),我们可能会提供更多帮助。 –

+0

我添加了一些代码作为演示 – Thomas

+0

用例描述有点不清楚; *为什么*你在迭代列表来查看密钥是否与刚收到的密钥相同?你是否试图保持帖子的顺序?如果是这样,只是每个帖子的时间戳,他们将始终在正确的顺序?此外,如果添加,更改或删除了某个帖子,则该帖子将传递给您的应用,从而再次直接访问该节点,因此无需遍历列表以查找它。即如果node_3被更改,该密钥(node_3)被传递给你的应用,你可以直接访问node_3/child_nodes来更新它们。 – Jay

回答

0

所以我莫名其妙地需要我的火力得到了本地的元素映射 表示它。

哦!这很容易!

如您所知,Firebase将其数据存储在键值对中。

因此,例如,一个用户节点将

users 
    uid_0 
     name: "Bill" 
    uid_1 
     name: "Larry" 

如果你在一个节点改名字,说比尔·比利的uid_0节点(及其子数据)传递给你的应用程序中快照,关键是uid_0。该键将对应于您存储在阵列中的数据。

有很多方法可以解决这个问题。

一种方式是存储对象的数组作为键值对字典英寸一些伪代码

myDictionary = [ "uid_0": [name: "Billy"] ] 
myArray[0] = myDictionary 

然而,“分类器”的方式来做到这将是创建一个用户类和存储那些在阵列中,与键(uid_0)作为类的属性之一

UserClass { 
    key = "" 
    name = "" 
} 

let aUser = UserClass 
aUser.key = snapshot.key 
aUser.name = snapshot.value("name") //loose pseudo code, dont copy/paste! 

myArray[0] = userClass 

然后,当您的应用程序收到快照时,您可以查询从snapshot.key收到的userClass.key的数组。

大图是Firebase通过密钥进行存储和访问,它保持一致并且不变,所以它是用来保持你的朋友的工具(消息s)阵列与Firebase同步。

编辑:如果您希望通过在HashMap(字典)中存储键和元素编号来直接访问已排序的数组对象,则可以实现链接列表。

Map<String, String> map = new HashMap<String, String>(); 
map.put("uid_0", "0"); 

然后打印出指数uid_0

System.out.println(map.get("uid_0")); 

其输出指数:0

如果你只想用一个存储机制,一个TreeMap(自然顺序)或LinkedHashMap是要走的路。

map.put("uid_0", *values for uid_0, name etc*); 
+0

感谢您的答案,但为snapshot.key找到相应的userClass.key我仍然需要迭代我的数组来找到它。不是吗?这是我目前的做法,只是没有课堂。总是找到匹配的userClass.key并保持排序仍然是很多代码(如我的文章所示)。 – Thomas

+0

我的歉意 - 我在高层发言,提供利用snapshot.key保持排列的背景。我更新了答案,提供了更多细节 - 我建议利用LinkedHashMap进行存储,因为您的数据可能是由Firebase在读取数据时订购的,并且LinkedHashMap将保持该顺序并且可以直接访问snapshot.key元素。 – Jay

+0

我也在考虑这个。但首先,据我所知,JavaScript不支持LinkedHasMaps。只有不保留订单的目录。另一点是,在视图内* ngFor(对于Angular)不能迭代地图。所以我需要编写一个单独的函数,将键作为数组提供,然后通过键引用我的目录中的确切条目。可悲的是,我在网上找到的所有教程只是简单地忽略了child_ *(除了child_added)事件。但必须有一个平滑的方式来解决这个问题在JavaScript(或打字稿)。 – Thomas