2

So I have a collection called "Drafts" which contains multiple documents each with an auto ID. Each document contains the fields "name" and "details". Each document is displayed in a tableViewCell under "nameLabel" and "detailsLabel". What I would like to do is when the user clicks on a button at the top of the screen of the First viewController, a copy of the collection "Drafts" is created and pasted under a new collection name called "Messages". This collection is then referencing the Second viewControllers tableViewCells just like on the First ViewController only this time its being referenced under the collection "Messages". Having done some research I have a vague inclination that the answer uses cloud functions to essentially create a copy of the collection and paste it with a new collection name. However being relatively new to coding and firebase, I have no idea how to do this and don't know if this is the correct solution. Please may someone help, any help is greatly appreciated!! Thanks!

First ViewController

func loadDrafts() {

    let userRef = db.collection("Users").document(user!)

    let draftsRef = userRef.collection("Drafts")

    exercisesRef.getDocuments { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            if let snapshot = querySnapshot {
                for document in snapshot.documents {
                    let data = document.data()
                    let name = data["name"] as? String ?? ""
                    let details = data["details"] as? String ?? ""
                    let newDrafts = DraftMessages(name: name, details: details)
                    self.array.append(newDrafts)
                }
                self.tableView.reloadData()
            }
        }
    }

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! DraftsCell

    cell.nameLabel.text = array[indexPath.row].name
    cell.detailsLabel.text = array[indexPath.row].details

    return cell
}

@IBAction func goButton(_ sender: UIButton) {

\\ Add code here to create copy of previous collection "Drafts" and paste in new collection "Messages"

}

Second ViewController

func loadData() {

    let userRef = db.collection("Users").document(user!)

    userRef.collection("Messages").getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            for document in querySnapshot!.documents {
                let data = document.data()
                let name = data["name"] as? String ?? ""
                let details = data["details"] as? String ?? ""
                let newMessages = Messages(name: name, details: details)
                self.array.append(newMessages)
            }
            self.tableView.reloadData()
        }
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MessagesCell

    cell.nameLabel.text = array[indexPath.row].name
    cell.detailsLabel.text = array[indexPath.row].details

    return cell

}
WH48
  • 737
  • 1
  • 7
  • 24
  • 1
    This can be done either in Swift or in Node.js on Cloud Functions (and probably half a dozen other technologies). Neither of these is pertinently better than the other. Asking us to pick one is a technology recommendation, which is off-topic on Stack Overflow because it attracts opions rather than factual answers. Pick the approach that you're most comfortable with (it seems that may be Swift), and implement the functionality. If you have problems along the way, report back with the [minimal code that reproduces where you got stuck](http://stackoverflow.com/help/mcve). – Frank van Puffelen Jun 10 '18 at 21:42
  • Hi Frank, thank you so much for the response. Swift is definitely my preference, but I've been trying/researching for weeks with no luck. Please may you get me started as I really stuck? Thanks! – WH48 Jun 10 '18 at 21:49
  • 1
    You're already reading the draft documents. So next step is to create a button click handler, looping over the same documents, and then writing them to a different collection. What specific part has you stumped? Can you limit your question to just that code? – Frank van Puffelen Jun 10 '18 at 22:50
  • Creating the button click handler that loops over the same documents has me stumped at the moment, unfortunately I have no code for it at the moment as I really am stumped! Would it be possible for you to help me out with the code? Thank you so much for the help so far, it’s really helped!! – WH48 Jun 10 '18 at 23:00
  • Hi Frank, finally managed to figure it out after working on it for sometime! Many thanks for the help again, its greatly appreciated! – WH48 Jun 11 '18 at 21:11

1 Answers1

3

Here is my working solution. Many thanks to Franks for the help!

@IBAction func goButton(_ sender: UIButton) {

    let userRef = db.collection("Users").document(user!)

    let draftsRef = userRef.collection("Drafts")

    draftsRef.getDocuments { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            if let snapshot = querySnapshot {
                for document in snapshot.documents {
                    let data = document.data()
                    let batch = self.db.batch()
                    let docset = querySnapshot

                    let messagesRef = userRef.collection("Messages").document()

                    docset?.documents.forEach {_ in batch.setData(data, forDocument: messagesRef)}

                    batch.commit(completion: { (error) in
                        if let error = error {
                            print("\(error)")
                        } else {
                            print("success")
                        }
                    })
                }
            }
        }
    }
}

Edit for Vaibhav Jhaveri:

This function (hopefully) both duplicates the fetched documents data and the data inside of that documents subcollection. (I have not tested this though)

func duplicate() {
    let userRef = db.collection("Users").document(userID)
    let batch = self.db.batch()

    let draftsRef = userRef.collection("Drafts")
    draftsRef.getDocuments { (snapshot, err) in
        if let err = err {
            print(err.localizedDescription)
            return
        }

        guard let snapshot = snapshot else { return }

        snapshot.documents.forEach({ (document) in
            let data = document.data()
            let messageID = UUID().uuidString

            let messagesRef = userRef.collection("Messages").document(messageID)
            batch.setData(data, forDocument: messagesRef, merge: true)

            let yourSubCollectionRef = draftsRef.document(document.documentID).collection("yourSubCollection")
            yourSubCollectionRef.getDocuments(completion: { (subSnapshot, subErr) in
                if let subErr = subErr {
                    print(subErr.localizedDescription)
                    return
                }

                guard let subSnapshot = subSnapshot else { return }

                subSnapshot.documents.forEach({ (subDocument) in
                    let subData = subDocument.data()
                    let subDocID = UUID().uuidString

                    let yourNewSubCollectionRef = userRef.collection("Messages").document(messageID).collection("yourSubCollection").document(subDocID)
                    batch.setData(subData, forDocument: yourNewSubCollectionRef, merge: true)
                })
            })
        })

        batch.commit()
    }
}
WH48
  • 737
  • 1
  • 7
  • 24
  • This just clones the fields, what about cloning the collections present in a document? – Vaibhav Jhaveri May 14 '19 at 13:15
  • @VaibhavJhaveri Does that mean you would like to know the answer to that question? Or are you saying I should of included that in my answer above? – WH48 May 14 '19 at 14:33
  • Yes, I would like to know the answer to my question. You can update your answer by including it – Vaibhav Jhaveri May 16 '19 at 07:16
  • 1
    @VaibhavJhaveri Please find above my answer, note that you need to know the string value for the sub collection field. Hope this helps – WH48 May 16 '19 at 07:38