Firebase按顺序获取数据

时间:2016-10-21 00:17:16

标签: swift firebase firebase-realtime-database

我正在使用Firebase,直到最近我才按字母顺序获取数据。我从不使用查询,我总是只使用数据快照并逐个排序。最近,数据并非始终按字母顺序排列在 snapVal 中。我如何制作它,以便按字母顺序排序数据的snapVal,就像它在数据库的快照中一样?

真实示例:有4条消息,id1-id4(按此顺序)。他们传达了信息" 1" - " 4"。快照看起来正确。但是snapVal(snapshot.value)看起来像这样:

["id2": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 2;
    TIME = "8:12 PM";
}, "id4": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 4;
    TIME = "8:12 PM";
}, "id1": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 1;
    TIME = "8:12 PM";
}, "id3": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 3;
    TIME = "8:12 PM";
}]

快照的样子:

["id1": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 1;
    TIME = "8:12 PM";
}, "id2": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 2;
    TIME = "8:12 PM";
}, "id3": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 3;
    TIME = "8:12 PM";
}, "id4": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 4;
    TIME = "8:12 PM";
}]

要获取snapVal,我使用它:

if let snapVal = snapshot.value as? [String: AnyObject] {
     // Comes out of order..
}

澄清:

快照(最终结果正确):

Snap (CHAT) {
    id1 =     {
        DATE = "10/20/16";
        "FIRST_NAME" = first;
        ID = userID;
        "LAST_NAME" = last;
        MESSAGE = 1;
        TIME = "8:12 PM";
    };
    id2 =     {
        DATE = "10/20/16";
        "FIRST_NAME" = first;
        ID = userID;
        "LAST_NAME" = last;
        MESSAGE = 2;
        TIME = "8:12 PM";
    };
    id3 =     {
        DATE = "10/20/16";
        "FIRST_NAME" = first;
        ID = userID;
        "LAST_NAME" = last;
        MESSAGE = 3;
        TIME = "8:12 PM";
    };
    id4 =     {
        DATE = "10/20/16";
        "FIRST_NAME" = first;
        ID = userID;
        "LAST_NAME" = last;
        MESSAGE = 4;
        TIME = "8:12 PM";
    };
}

这是print(snapVal.keys)if let snapVal = snapshot.value as? [String: AnyObject]的输出:

LazyMapCollection<Dictionary<String, AnyObject>, String>(_base: ["id2": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 2;
    TIME = "8:12 PM";
}, "id4": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 4;
    TIME = "8:12 PM";
}, "id1": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 1;
    TIME = "8:12 PM";
}, "id3": {
    DATE = "10/20/16";
    "FIRST_NAME" = first;
    ID = userID;
    "LAST_NAME" = last;
    MESSAGE = 3;
    TIME = "8:12 PM";
}], _transform: (Function))

我的代码:

  self.firebase.child("Chats").child(chatID).queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot) in
                          print(snapshot)
                        if let snapVal = snapshot.value as? [String: AnyObject] {

                            print(snapVal)

                            for c in snapVal {
                                print("checking Message as child")
                                let message = c.value["MESSAGE"] as? String

                                let fn = c.value["FIRST_NAME"] as? String
                                let ln = c.value["LAST_NAME"] as? String

                                let USER_ID = c.value["ID"] as? String

                                if let userID = USER_ID {
                                    if let msg = message {
                                        if let firstName = fn {
                                            if let lastName = ln {
                                                let username = "\(firstName) \(lastName)"
                                                self.addMessage(userID, text: msg, name: username)

                                                print("Message added! \nMessage Info:")
                                                print("User ID: \(userID)")
                                                print("text: \(msg)")
                                                print("Username: \(username)")
                                            } else {
                                                print("LN did not pass")
                                            }
                                        } else {
                                            print("FN did not pass")
                                        }
                                    } else {
                                        print("Msg did not pass")
                                    }
                                } else {
                                    print("User ID did not pass")
                                }
                            }
                          }  
})

4 个答案:

答案 0 :(得分:6)

由于你还没有分享必要的代码,我会假设你正在做这些事情:

ref!.queryOrdered(byChild: "text").observe(.value, with: { (snapshot) in
    print("\(snapshot.value)")
})

在Firebase位置执行查询时,将返回数据,其中包含有关根据查询的项目顺序的信息。当您观察到事件时,快照包含键,值和子项的顺序。

但是当您转换请求snapshot.value属性时,所有信息都必须转换为字典。每个孩子的钥匙和价值在这次转换中幸存下来,但有关订购的信息会丢失。

因此,您必须使用快照的children属性以正确的顺序迭代子项:

ref!.queryOrdered(byChild: "text").observe(.value, with: { snapshot in
    for child in snapshot.children {
        print("child \(child)")
    }
})

答案 1 :(得分:2)

根据我使用Firebase的经验,您无法保证快照值中返回数据的顺序。 Firebase提供了一些功能,您可以添加到参考查询中,然后根据键queryOrderedByKey,值queryOrderedByValue或子queryOrderedByChild对数据进行排序和排序。

根据您的描述,您可能希望使用queryOrderedByChild对快照进行正确排序。

这里有关于这些功能的文档,并向下滚动到排序数据部分。 https://firebase.google.com/docs/database/ios/lists-of-data

答案 2 :(得分:2)

解决方案:经过非常广泛的搜索和尝试后,问题仍然存在,一旦快照转换为snapVal(snapshot.value),订单通常会重新排列。我的(工作)解决方案:

for child in snapshot.children {
let child = child as! FIRDataSnapshot
 if let childVal = child.value as? [String: AnyObject] {
    let childMessage = childVal["MESSAGE"] as! String
    // more code for each child. This child might be a post of a sort, which you can access properties of in a way like I did in the line above
 }
}

<强>过程

  1. 循环播放快照中的每个孩子

  2. 将子项转换为FIRDataSnapshot,因此它不是元素

  3. 获取特定子项的值以访问属性
  4. 按照NSDictionary原则添加孩子的相应代码。

  5. 为什么此解决方案是可靠的

    以正确的顺序接收快照非常简单。我遇到的问题是在获得snapshot.value时以正确的顺序获取数据。此解决方案修复了这一问题,因为只有在循环遍历快照的子项时才会访问每个子项的值。这使得孩子的顺序仍然在快照的控制之下。

    我也喜欢snapshot.value使用[String: AnyObject]方法,因为它非常接近Swift中Firebase实现的旧功能:简单而且非常干净。我实际上认为以这种方式使用NSDictionary实际上是一种节省时间的方法,因为它不会以任何方式冗长。

答案 3 :(得分:0)

您可以看到的问题不是Firebase没有按要求为您提供排序响应,问题是您正在将响应解析为字典而字典不是有序列表。解决它的最简单方法是使用以下内容订购字典:

self.messages.sortInPlace({ ($0.date.compare($1.date) == NSComparisonResult.OrderedAscending)}) 

或者更好的方法是将结果直接添加到数组中。 您可以在我的课程中找到有关此问题的更多信息,在那里进行了长时间的讨论(https://www.udemy.com/firebase/learn/v4/questions/1341056)。

如果有帮助,请告诉我。