michaeldebo
michaeldebo

Reputation: 3195

How to store an array of objects in Firestore

I can't find online how to store an array of objects so that the key "line_items" presents numbers for each menuItem with values for each menuItem corresponding to its own number. In other words, I need the numbers to come after line_items rather than the nested key so that each individual MenuItem object can be quickly referenced. I found online how to make it so each key has an array of values, but I need line_items to have an array of MenuItem objects. The following code crashes:

public func uploadTransactionData(_ menuItems: [MenuItem], balanceId: String, subTotal: Int, completion: @escaping (() -> ())) {
    guard let userId = Auth.auth().currentUser?.uid else { completion(); return }
    let utilitiesManager = UtilitiesManager()
    let timestamp = utilitiesManager.timestamp()
    let params: [String: Any] = ["date": "\(timestamp)",
        "balance_id": "\(balanceId)",
        "subtotal": "\(subTotal)",
        "user_id": "\(userId)",
        "line_items": menuItems
    ]
    Firestore.firestore().document("transaction_history/\(timestamp)").setData(params)
    { err in
        if let e = err {
            print("$-- error creating user \(e)")
            completion()
        } else {
            completion()
        }
    }
}

Here's the MenuItem model:

struct MenuItem {

let itemId: String
let name: String
var modifiers: [String]?
var photoName: String?
var photoUrl: String?
var quantity: Int
var price: Int
var sizeAddOnPrice: Int
var toppingsAddOnPrice: Int
let description: String
var size: String
let category: String

init(itemId: String, name: String, modifiers: [String]?, photoName: String?, photoUrl: String?, quantity: Int, price: Int, sizeAddOnPrice: Int, toppingsAddOnPrice: Int, description: String, size: String, category: String) {
    self.itemId = itemId
    self.name = name
    self.modifiers = modifiers
    self.photoName = photoName
    self.photoUrl = photoUrl
    self.quantity = quantity
    self.price = price
    self.sizeAddOnPrice = sizeAddOnPrice
    self.toppingsAddOnPrice = toppingsAddOnPrice
    self.description = description
    self.size = size
    self.category = category
}

Upvotes: 1

Views: 5581

Answers (2)

Bhaumik
Bhaumik

Reputation: 1238

Problem:

Your app is crashing because you are trying to save user defined object MenuItem to Firestore. Firestore doesn't allow it. Firestore only supports this datatypes.

Solution:

You can convert your custom object MenuItem to Firestore supported datatypes. You can do this by making following changes to your code.

  1. Make MenuItem confirm to Codable protocol.

    struct MenuItem: Codable { 
         // Your code as it is.
    }
    
  2. Make following changes to your uploadTransactionData() function:

    public func uploadTransactionData(_ menuItems: [MenuItem], balanceId: String, subTotal: Int, completion: @escaping (() -> ())) {
    let userId = Auth.auth().currentUser?.uid else { completion(); return }
    let utilitiesManager = UtilitiesManager()
    let timestamp =  utilitiesManager.timestamp()
    
    var list_menuItem = [Any]()
    for item in menuItems {
        do {
            let jsonData = try JSONEncoder().encode(item)
            let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: [])
            list_menuItem.append(jsonObject)
        }
        catch {
            // handle error
        }
    }
    
    let params: [String: Any] = ["date": "\(timestamp)",
        "balance_id": "\(balanceId)",
        "subtotal": "\(subTotal)",
        "user_id": "\(userId)",
        "line_items": list_menuItem
    ]
    
    
    Firestore.firestore().document("transaction_history/\(timestamp)").setData(params) 
        { err in
            if let e = err {
                print("$-- error creating user \(e)")
                completion()
            } else {
                completion()
            }
        }
    }
    

Upvotes: 4

Stijnk008
Stijnk008

Reputation: 232

This is because Firestore doesn't know how to save the value: menuItems

you can map it like this: "objectExample": [
    "a": 5,
    "b": [
        "nested": "foo"
    ]
]

or:

.setData([
"name": "Frank",
"favorites": [ "food": "Pizza", "color": "Blue", "subject": "recess" ],
"age": 12
])

Upvotes: 0

Related Questions