Firebase Firestore混乱数组顺序

时间:2018-03-05 21:06:43

标签: swift firebase google-cloud-firestore

我使用Firebase的Firestore存储我的iOS应用程序的数据。在Firestore中,我有两个集合。一个叫songs,一个叫playlistssongs集合包含许多文档,每个文档内部都有一个歌曲信息。这是songs文档的样子。

songs documet

然后,在我的收藏集playlists中,它包含一些作为播放列表的文档。这是playlists文档的示例。

playlists document

我希望能够显示播放列表,然后从我的songs集合中获取该播放列表中的歌曲标题。所以,我已经做到了这一点:

var testPlaylistTitles = [String]()
db.collection("playlists").whereField("title", isEqualTo: "Test Playlist").getDocuments { (snapshot, error) in

       for document in (snapshot?.documents)! {
           self.testPlaylistTitles = ((document.data()["songTitles"] as? [String])!)

                }
          }

这使得变量testPlaylistTitles = ["Test Song", "Test Song 2", "Test Song 3"]。这很棒。但这是出错的地方。我希望从songs集合中获取有关这些歌曲的信息。因此,我创建了一个for循环并循环播放歌曲以附加到我的其他艺术家,图像和标题阵列。就本例而言,我将使用returedTitles的变量。

var testPlaylistTitles = [String]()
db.collection("playlists").whereField("title", isEqualTo: "Test Playlist").getDocuments { (snapshot, error) in

       for document in (snapshot?.documents)! {
           testPlaylistTitles = ((document.data()["songTitles"] as? [String])!)

                }
       var returedTitles = [String]()
       for i in 0...testPlaylistTitles.count-1 {
       db.collection("songs").whereField("title", isEqualTo: testPlaylistTitles[i]).getDocuments(completion: { (snapshot, error) in
                    for document in (snapshot?.documents)! {
                        returedTitles.append((document.data()["title"] as? String)!)

                    }
                })
           } 
   }

现在,returedTitles等于原始testPlaylistTitles的随机播放版本。我一开始认为它不知何故是按字母顺序排序testPlaylistTitles,但它不是。有没有人对正在发生的事情以及如何解决它有任何想法!非常感谢!这让我感到很沮丧。

3 个答案:

答案 0 :(得分:1)

我不知道如何在swift中执行此操作,但我会将播放列表文档中歌曲的数据结构更改为歌曲为键的对象和值的顺序,然后在第二个循环中在您的查询中,您使用键来返回值,您应该能够按值排序。

{ 
  description: "test",
  songs: {
    "Test Song 1": 1,
    "Test Song 2": 3,
    "Test Song 4": 2
  },
  title: "Test playlist"
}

我还建议使用列表中歌曲的ID,因为您在以后的某个阶段检索数据。

答案 1 :(得分:0)

看起来你依赖于for循环中查询的执行顺序。请记住,getDocuments()是异步,这意味着它会立即返回,结果会在一段时间后出现在回调中(无法保证需要多长时间)。因为它是异步的,所以你有效地同时开始testPlaylistTitles.count nubmer查询,每个查询都不考虑另一个。因此,您正在构建的数组将以未定义的顺序累积结果。为了帮助可视化,请在每个回调中放置一条日志消息,以查看它们实际调用的顺序。每次都包括数组的内容,以查看数组的构建方式。

如果结果的顺序很重要,您需要弄清楚自己的订单是什么。如果这意味着按顺序依次执行查询(这将是整体性能命中),那么您将必须以这种方式编码。

但最重要的是,你需要仔细考虑做异步工作。有关Firebase API异步原因的详细信息,请Please read this blog

答案 2 :(得分:0)

Doug指出,问题在于调用是异步的,因此它们不一定按照启动顺序添加到数组中 - 它们会在数据可用时添加。有几种方法可以解决这个问题,但是一个让你开始的建议是初始化你的数组,使它们的大小等于testPlaylistTitles的大小。然后,当您获得数据时,将其插入数组中的特定位置,而不是将其附加到数组的末尾。

var testPlaylistTitles = [String]()
db.collection("playlists").whereField("title", isEqualTo: "Test Playlist").getDocuments { (snapshot, error) in

   for document in (snapshot?.documents)! {
       testPlaylistTitles = ((document.data()["songTitles"] as? [String])!)

            }
   var returedTitles = [String](repeating: "title", count: testPlaylistTitles.count)
   for i in 0...testPlaylistTitles.count-1 {
       db.collection("songs").whereField("title", isEqualTo: testPlaylistTitles[i]).getDocuments(completion: { (snapshot, error) in
            if (snapshot!.documents.count) > 0 {
                    let doc = (snapshot?.documents.first)!
                    returedTitles[i] = ((doc.data()["title"] as? String)!)

                }
            })
       } 
}

在此代码中,我初始化了一个大小为testPlaylistTitles的数组。每个索引的价值仅为" title"首先,然后在下载后使用Firestore中的值替换它。