Home > Back-end >  How to push updated local JSON file to Firebase in swiftui?
How to push updated local JSON file to Firebase in swiftui?

Time:05-22

I have updated my local JSON file but I cannot figure out why it is not being pushed to Firebase? For example, I created JSON file and used placeholder text just to see how it would look in the UI. I pushed the placeholder text to Firebase but when I updated my JSON file in Xcode, it did not get pushed and updated in Firebase. Do I need to make a new push method for that particular key/value pair?

Here is an example of what I pushed initially with the placeholder text

"id": 1,
        "category": "Cardiovascular",
        "course": {
            "id": 1,
            "image": "cardiovascular",
            "description": "This quiz goes over the cardiovascular system.",

Here is the update to description that I want to push to Firebase.

"id": 1,
        "category": "Cardiovascular",
        "course": {
            "id": 1,
            "image": "cardiovascular",
            "description": "The Cardiovascular system transports blood containing oxygen, nutrients, and other substances (e.g., hormones, electrolytes, and drugs) to the tissues of the body, whereas at the same time facilitating the removal of carbon dioxide and other waste products from the body. It also assists in temperature regulation. The primary components of the cardiovascular system include the heart, arteries, arterioles, capillaries, venules, veins, and blood. The heart is comprised of cardiac muscle and nervous tissue that fat generates the force that propels the blood through the body.",

Here is the method to push to Firebase

func pushToFirebase(quizmodules: [Quiz]){
        let db = Firestore.firestore()
        
        let firebaseModules = db.collection("quizmodules")
        
        for quiz in quizmodules {
            let course = quiz.course
            let test = quiz.course.test
            
            let firebaseModule = firebaseModules.addDocument(data: ["category": quiz.category])
            
            firebaseModule.updateData(["id": firebaseModule.documentID,
                                       "course": ["id": firebaseModule.documentID,
                                        "image": course.image,
                                                  "description": course.description,
                                                  
                                        ],
                                       "test": [
                                        "id": firebaseModule.documentID,
                                        "questions": test.questions.count
                                       ]
                                      ])
            
            
            
            
            for question in test.questions {
                let firebaseQuestion = firebaseModule.collection("questions").addDocument(data: ["content": question.content,
                                                                                                 "correctIndex": question.correctIndex,
                                                                                                 "answers": question.answers
                                                                                                 
                ])
                
                firebaseQuestion.updateData(["id": firebaseQuestion.documentID])
            }
            
        }
    }

CodePudding user response:

Let me restate the question to make sure I am answering correctly:

I am writing a document to Firestore and want to update that document at a later time

When you want to update a specific document in Firestore, you need to know the documentId of the document you want updated.

So here's the issue

let firebaseModule = firebaseModules.addDocument(data:

.addDocument creates a new document each time it's run so the following .update call updates the document that was just created. The next time the code is run a totally new document is created.

Also, and maybe this is intentional, the .addDocument call creates documents with a field category

["category": quiz.category])

and then just adds a bunch more fields to that same document.

firebaseModule.updateData(["id": firebaseModule.documentID,
                           "course": ["id": firebaseModule.documentID,

so every document looks the same

some_document_id
     category: some value
     course: [
              description: some value

that could be simplified by just creating the document with the fields in the addDocument call.

So - how to fix. Here's a very brief example that creates an initial document with a documentId of my_document

let tempCollection = self.db.collection("my_collection")
let myDocument = tempCollection.document("my_document")
myDocument.setData(["field0": "data0",
                    "field1": "data1"])

At a later time in your code, you want to update the values of field0 and field1 of my_document. Here's how to do that

let tempCollection = self.db.collection("my_collection")
let myDocument = tempCollection.document("my_document")
myDocument.updateData(["field0": "new data0",
                       "field1": "new data1"])

The important bit is that the document being updated has the same documentId (my_document) as in the code that created the document.

CodePudding user response:

If you adopt some of the new Firestore Wrappers that are provided with FirebaseFirestoreSwift you can save some of the complications.

Your model structs would change a little too

struct Quiz: FirestoreCodable{
    @DocumentID var id: String?
    var category: String
    var course: Course
}
struct Course: FirestoreCodable{
    @DocumentID var id: String?
    var image: String
    var description: String
}

FirestoreCodable is just a protocol to make your methods generic (reusable)

public protocol FirestoreCodable: Decodable, Encodable{
    /// Wrap with `@DocumentID` from `import FirebaseFirestoreSwift`
    var id: String? { get set }
}

Then you can add documents with

///Adds the object to the collection, returns the `id` for the newly created document
public func create<FC : FirestoreCodable>(path: String, object: FC) throws -> String?{
    let reference = try store.collection(path).addDocument(from: object)
    return reference.documentID
}

then use it

let documentId = try create(path:"quizmodules", object: quiz)

And update documents with

public func update<FC : FirestoreCodable>(path: String, object: FC) throws{
    guard let id = object.id else{
        throw PackageError.needValidId
    }
    try store.collection(path).document(id).setData(from: object)
}

then use it

try update(path:"quizmodules", object: quiz)

or

public func update<V: Hashable>(path: String, id: String, variableName: String, value: V) throws{

    let reference = store.collection(path).document(id)
    reference.updateData([
        variableName: value
    ])
}

then use it

try update(path:"quizmodules", id: quiz.id, variableName: "course", value: course)

Note that quiz and course would be an object of type Quiz or Course

Once you have the basic setup going you can also use

@FirestoreQuery(collectionPath: "quizmodules") 

to listen for changes to the collection.

  • Related