Andrew0
Andrew0

Reputation: 37

Swift Firestore retrieve data

I want make QuoteApp with such a structure example :

{
    "Books": {
        "firstBook": {
            "Quotes": {
                "Quote1": "",
                "Quote2": "",
                "Quote3": ""
            },
            "name": "firsBook"
        },
        "secondBook": {
            "Quote": {
                "Quote1": "",
                "Quote2": "",
                "Quote3": ""            
    },
            "name": "secondBook"
        }
    },
     "Serials": {
        "firstSerial": {
            "Quote": {
                "Quote1": "",
                "Quote2": "",
                "Quote3": ""
            },
            "name": "firsSerial"
        },
        "secondSerial": {
            "Quote": {
                "Quote1": "",
                "Quote2": "",
                "Quote3": ""
            },
            "name": "secondSerial"
        }
    }

I created a structure in Firestore

I have Category -> documents (Books, Film, Serial) in which there is "name" and contains collections (firstFilm, secondFilm...) -> documents in which there is "quote"

https://i.sstatic.net/wp0pu.png

https://i.sstatic.net/KhFSq.png

I put category name to tableView like this:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var myTableView: UITableView!

    var array: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        myTableView.delegate = self
        myTableView.dataSource = self

        let db = Firestore.firestore()
        db.collection("Category").getDocuments { (snapshot, error) in
            if error != nil {
                print(error)
            } else {
                for document in (snapshot?.documents)! {
                    if let name = document.data()["name"] as? String {
                    self.array.append(name)
                        DispatchQueue.main.async {
                            self.myTableView.reloadData()
                        }
                    }
                }
            }
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return array.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let category = array[indexPath.row]
        cell.textLabel?.text = category
        return cell
    }

Its work good, but how can I catch and put data to another View, form didSelectItemAt indexPath func and show From Films -> tap -> show all collections (firstFilm+ secondFilm...)

Upvotes: 1

Views: 1587

Answers (1)

Serj
Serj

Reputation: 684

Hey there Andrew I'm going to give you the answer to what you asked and then also make you reconsider the way you have designed out your Firestore schema as its not optimal at all and will get very complex easily and Firestore does warn of this here:

https://firebase.google.com/docs/firestore/manage-data/structure-data

Now since firstFilm and firstBook and all the other first_ are collections you will need to call another fetch on the Firestore like this to get the contents of that first_ (keep in mind the contents and not the collections itself) like this:

db.collection("Category").document("Film").collection("firstFilm").getDocuments

Also to make things more general usually this is the pattern that Firestore follows:

db.collection("Collection Name").document("documentId").collection("Collection Name").....

As you can see since first_ second_ are collections you can't fetch them to show in your next table view to the user to select first_ second_. You would statically need to add these to your app so that you can show to the user that he can select something called first_. This is bad because lets say you add an Article category tomorrow you would to statically add firstArticle, secondArticle, thirdArticle.

Moreover the documentId mentioned above is retrievable from snapshot?.documents.documentID. You would need to keep reference to it to be able to complete the path to fetch the rest of the nested objects in your initial collection.

So the answer is to show firstFilm, secondFilm, thirdFilm you would need to handle this manually as Firestore won't return what collections exist in a document, you have to manually reference these collections and give a path to Firestore to fetch the documents at that path.

Now as you might realized that the way you have designed is not very optimum and not scalable. I really suggest that you find a way to design more generically so you could make the best of Firestore. Do go over the Firestore documentation and put more thought into it.

My initial suggestion might be instead of making firstFilm, secondFilm collections make a field in Film that takes an Array of Films. Then that way you could pass the films to the second view controller and create the table view in your second view controller. However, still this might not be optimum you can make it still more generic if you try harder.

Upvotes: 1

Related Questions