【问题标题】:Firebase getting data in orderFirebase 按顺序获取数据
【发布时间】:2017-03-03 03:57:51
【问题描述】:

我正在使用 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")
                                }
                            }
                          }  
})

【问题讨论】:

  • 没有看到minimal code + data that reproduces the problem 将很难提供帮助。
  • @FrankvanPuffelen 我的代码是正确的。问题是我的数据快照中的数据片段乱序。
  • @FrankvanPuffelen 我更新了问题,让您更好地了解我的问题
  • @FrankvanPuffelen 我再次更新了问题。快照是正确的,但 snapshot.value 是乱序的,这是为什么呢?
  • 请更新以包含实际检索快照的代码。不要说“乱序”,而是显示它们出现的顺序(print(snapshot.key) 语句通常对此非常有效)以及您期望它们出现的顺序。

标签: swift firebase firebase-realtime-database


【解决方案1】:

由于您没有共享必要的代码,我假设您正在按照以下方式进行操作:

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

当您对 Firebase 位置执行查询时,会根据查询返回数据以及有关项目顺序的信息。当您观察 value 事件时,快照包含键、值和子项的顺序。

但是当您转换请求snapshot.value 属性时,所有信息都必须转换为字典。每个孩子的键和值在此转换中仍然存在,但有关排序的信息会丢失。

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

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

【讨论】:

  • 请查看我的代码,我更新了问题以将其包含在最后。请注意,我通过键对查询进行了排序,但它在snapshot.value 中仍然出现故障。我也相信我需要像以前一样(在String: AnyObject 中)使用 NSDictionary 来正确访问子项中的值。
  • 顺便说一句,你过去和现在对我的问题都非常有帮助,我只想说谢谢你。 @FrankVanPuffelen
【解决方案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 原则为孩子添加相应的代码。

为什么这个解决方案是可靠的

以正确的顺序接收快照非常简单。我遇到的问题是当我收到snapshot.value 时以正确的顺序获取数据。该解决方案解决了这个问题,因为每个子项的值仅在遍历已排序的快照的子项时才被访问。这使得孩子的顺序仍然在快照的控制之下。

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

【讨论】:

    【解决方案3】:

    根据我使用 Firebase 的经验,您无法保证数据在快照值中返回的顺序。 Firebase 提供了几个函数,您可以将它们添加到参考查询中,但可以根据键 queryOrderedByKey、值 queryOrderedByValue 或子 queryOrderedByChild 对数据进行排序和排序。

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

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

    【讨论】:

    • 我对快照非常熟悉,但对查询不熟悉,这使我不得不重新编写大量代码。此外,快照以正确的顺序返回。快照和 snapVal 之间只是发生了一些问题,其中 snapVal 以不同的顺序结束
    • 我也经历过同样的行为。不知道为什么它们不同。我自己只使用过几次排序功能。大多数情况下,我处理的数据都足够小,我从快照值创建一个对象/结构,将其存储在一个数组中,然后在其上运行 map 或 flatMap 以按我想要的方式对其进行排序。可能不是最好的方法,但到目前为止我的几个用例都有效。
    • 我添加了这个,不幸的是它对我没有帮助。请查看我的代码以了解我的方法。
    【解决方案4】:

    您可以看到的问题不是 Firebase 没有按要求为您提供排序的响应,问题是您将响应解析为字典,而字典不是有序列表。修复它的最简单方法是使用以下命令对字典进行排序:

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

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

    如果这对你有帮助,请告诉我。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-16
      • 2019-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多