Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift iOS - Add data as custom model containing custom model to Firestore

So I have two custom model classes. One is a Story and the other is Page. The Story contains multiple properties including an array of pages.

struct Story {

var name: String
var pages: [Page]
var tags: [String]
var likes: [String]
var isPrivate: Bool

var dictionary: [String: Any] {
    return [
        "name": name,
        "pages": pages,
        "tags": tags,
        "likes": likes,
        "isPrivate": isPrivate,
    ]
}

struct Page {

let thumbnail: String
let image: String?
let video: String?

var dictionary: [String: Any] {
    return [
        "thumbnail": thumbnail,
        "image": image as Any,
        "video": video as Any
    ]
}

When I upload to Firebase I basically I want the pages object to be a subcollection within the Story object. But I am confused on how I would correctly do this in such a way that I can have the models properly map and decode from the Firebase Response.

The only way I can think of doing this is to create a Story on the database, get a callback with the ID and then create the page within that. The problem is that my Story model wouldn't then include the custom Page model

like image 818
Niall Kiddle Avatar asked Apr 01 '19 16:04

Niall Kiddle


2 Answers

For what it's worth, anyone winding up here via Google looking for custom data model handling + Swift + Firebase should check out this feature of Firebase using the Codable protocol.

https://firebase.google.com/docs/firestore/manage-data/add-data#custom_objects

Specifically this gives you access to a special setData call that looks like document("LA").setData(from: city).

You should not need the extra import anymore in Firebase v7.3+ so that's awesome! If you're still on v6 or older, you need it.

If you don't have access to this function in your code, it's because you need to import FirebaseFirestoreSwift which are special extensions for Swift prior to v7.0.

like image 200
BigMcLargeHuge Avatar answered Sep 25 '22 03:09

BigMcLargeHuge


First, you don't need to write to Firestore to get the auto-generated Id of that document. Firestore auto generates Ids on the client (it's a combination of timestamp and random).

Second, you may want to consider adding a property to Story that carries the array of pages in dictionary format:

struct Page {

    let thumbnail: String
    let image: String?
    let video: String?

    var dictionary: [String: Any] {
        return [
            "thumbnail": thumbnail,
            "image": image as Any,
            "video": video as Any
        ]
    }

}

struct Story {

    var name: String
    var pages: [Page]
    var pagesData: [[String: Any]] // I added this for convenience
    var tags: [String]
    var likes: [String]
    var isPrivate: Bool

    var dictionary: [String: Any] {
        return [
            "name": name,
            "pages": pages,
            "tags": tags,
            "likes": likes,
            "isPrivate": isPrivate,
        ]
    }

}

Then create your pages as normal:

let page1 = Page(thumbnail: "abc", image: nil, video: nil)
let page2 = Page(thumbnail: "xyz", image: nil, video: nil)

Create a story and inject the pages into it, including the datafied version:

let story = Story(name: "Story", pages: [page1, page2], pagesData: [page1.dictionary, page2.dictionary], tags: ["kiwi", "mango"], likes: ["x", "y"], isPrivate: false)

Use Firestore to generate a random identifier:

let docRef = Firestore.firestore().collection("someCollection").document()
let docId = docRef.documentID

You can now inject this identifier into every object before writing to Firestore if you need them to share it.

Create the data object that will be written to Firestore:

let data: [String: Any] = [

    "name": story.name,
    "pages": story.pagesData
    // etc

]

In the backend, the pages field will be an array of maps.

Then just write the data to Firestore:

docRef.setData(data) { (error) in

    if let error = error {
        print("🤬 \(error)")
    } else {
        print("👌")
    }

}
like image 36
liquid LFG UKRAINE Avatar answered Sep 25 '22 03:09

liquid LFG UKRAINE