【问题标题】:Retrieve data from "getDocument" query inside another "getDocument" query从另一个“getDocument”查询中的“getDocument”查询中检索数据
【发布时间】:2018-10-11 09:53:18
【问题描述】:

我的代码从 Firestore 检索数据时遇到问题。

我的代码中有 2 个类:Exercise 和 Tag。 我的 FirestoreDatabase 中有 2 个集合:练习和标签

我需要从“练习”集合中获取所有“练习”文档。每个“练习”文档都有一个名为“标签”的字段,它是一个字符串数组。数组的每个字符串都包含引用“tag”在“tags”集合中的文档的“id”。因此,在“tags”集合中查询这个 id,使我能够获得正确的“tag”文档并访问其所有数据。这正是我想要在我的代码中做的。

我需要将所有练习添加到一个练习对象中,为此我必须在另一个 getDocument 查询中使用 getDocument 查询,以便从“标签”集合中获取练习的“标签”

这是我的课程标签和练习:

class Tag {  
var id: String?
var type: String?
var description: String?

init(id: String, type: String, description: String) {
    self.id = id
    self.type = type
    self.description = description
  }
}

class Exercise {
   let id: String?
   let group: String?
   let tags: [Tag]
   let title : String!

   init(id: String, group: String, tags: [Tag], title: String){  
    self.id = id
    self.group = group
    self.tags = tags
    self.title = title   
  }

}

这是我从 Firestore 数据库中获取“练习”的代码:

func fetchExercises(completion: @escaping ([Exercise]) -> ()) {

    let exercisesRef = Firestore.firestore().collection("exercises")

    exercisesRef.getDocuments() { (querySnapshot, err) in

        var exercisesArray = [Exercise]()

        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            for document in querySnapshot!.documents {
                //print("\(document.documentID) => \(document.data())")

                let myData = document.data()
                let exercise_ID = document.documentID
                let exercise_group = myData["Group"] as! String
                let tagsArray = myData["Tags"] as! [String]

                var exercise_tags: [Tag] = [Tag]()

                for tag in tagsArray {
                    let tagID: String = tag
                    fetchTagfromID(tagID: tagID) { (tag: Tag) in
                        exercise_tags.append(tag)
                    }
                }

                let exercise_title = myData["Title"] as! String                 

                exercisesArray.append(Exercise(id: exercise_ID,
                                               group: exercise_group,
                                               tags: exercise_tags,
                                               title: exercise_title,
                ))
            }
            DispatchQueue.main.async{
               print("EXERCISE FETCH HAS FINIS")
                completion(exercisesArray)
            }
        }
    }
}


func fetchTagfromID(tagID: String, completion: @escaping (Tag) -> ()) {


let tagRef = Firestore.firestore().collection("tags").document(tagID)

tagRef.getDocument() { (document, err) in

    if let err = err {
        print("Error getting documents: \(err)")
    } else {

        let myData = document?.data()

        let tagDescription: String = myData!["description"] as! String
        let tagType: String =  myData!["type"] as! String
        let tag: Tag = Tag(id: tagID, type: tagType, description: 
tagDescription)


        DispatchQueue.main.async{
            print("TAGS FETCH HAS FINISHED")
            completion(tag)
        }
    }
  }
}

我的问题在于执行时间(队列)代码。

我需要先填写“exercise_tags”(辅助 getDocument 查询),然后继续并完成 fetchExercise(主要 getDocument 查询),但 Firestore 不允许(或不知道如何)这样做。代码首先完成主 getDocument 查询 (fetChExercises),然后返回完成辅助 getDocument 查询 (fetchTagfromID)。

总之,我需要在运行时得到这个日志:

TAGS FETCH HAS FINISHED
EXERCISES FETCH HAS FINISHED

现在我的情况正好相反。

你们知道如何解决这个问题吗?也许改变调度队列......

我现在如何分两步解决这个问题,但优雅的解决方案是一步完成所有事情。这就是 fetchExercises。

谢谢!

【问题讨论】:

    标签: ios swift google-cloud-firestore


    【解决方案1】:

    所以你需要做的是获取一个练习的所有标签,然后获取另一个练习。毕竟 fetch 调用完成处理程序来更新 UI。我对代码做了一些更改,您可以检查一下。

       var exercisesArray = [Exercise]()
       var listFromFetchExercise = []()  //it will contain all object of array 
       querySnapshot!.documents. set DataType according to that.
       var completion_exercises_Listner: () -> ()
    
       func fetchExercises(completion: @escaping ([Exercise]) -> ()) {
    
       let exercisesRef = Firestore.firestore().collection("exercises")
    
    exercisesRef.getDocuments() { (querySnapshot, err) in
    
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
    
            listFromFetchExercise = querySnapshot!.documents
            fetchAllExercise()
    
            DispatchQueue.main.async{
               print("EXERCISE FETCH HAS FINIS")
                completion(exercisesArray)
            }
        }
    }
    }
    
    func fetchAllExercise(completion: @escaping ([Exercise]) -> ()){
    
    fetchExercise()
    completion_exercises_Listner = {
        completion(exercisesArray);
    }
    
    }
    
    func fetchExercise(index:Int = 0) {
    
      let document = listFromFetchExercise[index]
    
      let myData = document.data()
      let exercise_ID = document.documentID
      let exercise_group = myData["Group"] as! String
      let tagsArray = myData["Tags"] as! [String]
    
      var exercise_tags: [Tag] = [Tag]()
    
      fetchTagsFromIDS(tagsArray) { (tag: [Tag]) in
      exercise_tags.append(contentsOf: tag)
    
      let exercise_title = myData["Title"] as! String                 
    
      exercisesArray.append(Exercise(id: exercise_ID,
                                   group: exercise_group,
                                   tags: exercise_tags,
                                   title: exercise_title,
    
       DispatchQueue.main.async{
          exercisesArray.append(tag)
          if (index + 1) < exercisesArray.count {
            fetchExercise(index+1,)
          }else{
            //Done
            completion_exercises_Listner()
          }
    
      }
       ))
    
      }
    
    
    
     var listofTags = [String]()
     var resultofTags = [Tag]()
    
       func fetchTagsFromIDS(tagIDS:[String],completion: @escaping (_ tags:[ 
     String]) -> ()){
    
    listofTags = tagIDS;
    fetchTagfromID() //Start With first tag
    
    completionListner = {
        completion(resultofTags);
    }
    
    }
    
    var completionListner: () -> ()
    
    func fetchTagfromID(index:Int = 0) {
    
     let tagRef = Firestore.firestore().collection("tags").document(tagID)
    
     tagRef.getDocument() { (document, err) in
    
    if let err = err {
        print("Error getting documents: \(err)")
    } else {
    
        let myData = document?.data()
    
        let tagDescription: String = myData!["description"] as! String
        let tagType: String =  myData!["type"] as! String
        let tag: Tag = Tag(id: tagID, type: tagType, description: 
       tagDescription)
    
    
        DispatchQueue.main.async{
            print("TAGS FETCH HAS FINISHED")
            resultofTags.append(tag)
            if (index + 1) < listofTags.count {
              fetchTagfromID(index+1,)
            }else{
              //Done
              completionListner()
            }
            //completion(tag)
        }
    }
    } }
    

    【讨论】:

    • 感谢您的及时回复。我会尽快测试。但是,与此同时,我想解决一个疑问。你的代码有效而我的无效?我的意思是,从我的无知来看,我看到你已经将这个过程分成了更多的步骤(子功能),但重点是一样的。让您的代码工作并等到从练习中提取所有标签的主要区别是什么?
    • 所以主要的不同是你在你的问题中提到'exercise_tags'需要首先然后继续完成fetchExercise方法。这样我的代码就可以了。因此,在我的代码中,您可以在 querySnapshot!.documents 获取时看到我所做的是一一获取所有练习。当我获取第一个练习时,我将调用 fetchTagsFromIDS 以获取所有标签以进行练习,然后我将继续进行另一个练习。所以它会等到所有的运动标签完成,然后它会在你的应用程序中获取你想要的另一个运动。调试代码你会理解的代码过程。
    • 好的,我明白了,非常感谢您的提问。它解决了这个问题。但是,我确信这必须是一个允许在同一函数中执行此操作的解决方案。我会继续调查。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多