Как сохранить массив объектов в Firestore

#ios #swift #firebase #google-cloud-firestore

#iOS #swift #firebase #google-облако-firestore

Вопрос:

Я не могу найти в Интернете, как сохранить массив объектов так, чтобы ключ «line_items» представлял числа для каждого элемента меню со значениями для каждого элемента меню, соответствующими его собственному номеру. Другими словами, мне нужно, чтобы после line_items шли числа, а не вложенный ключ, чтобы можно было быстро ссылаться на каждый отдельный объект MenuItem. Я нашел в Интернете, как сделать так, чтобы каждый ключ имел массив значений, но мне нужно, чтобы line_items имел массив объектов MenuItem. Происходит сбой следующего кода:

 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()
        }
    }
}
  

Вот модель MenuItem:

 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
}
  

Комментарии:

1. Не могли бы вы, пожалуйста, добавить, какую ошибку вы получаете?

2. *** Завершение работы приложения из-за неперехваченного исключения ‘FIRInvalidArgumentException’, причина: ‘Неподдерживаемый тип: _SwiftValue’

3. Firestore никогда не узнает, что такое MenuItem. Пожалуйста, взгляните сюда: firebase.google.com/docs/firestore/manage-data/data-types это типы данных, поддерживаемые Firestore.

Ответ №1:

Проблема:

Ваше приложение выходит из строя, потому что вы пытаетесь сохранить пользовательский объект MenuItem в Firestore. Firestore этого не позволяет. Firestore поддерживает только эти типы данных.

Решение:

Вы можете преобразовать свой пользовательский объект MenuItem в типы данных, поддерживаемые Firestore. Вы можете сделать это, внеся следующие изменения в свой код.

  1. Сделайте MenuItem подтверждение Codable протоколу.

     struct MenuItem: Codable { 
         // Your code as it is.
    }
      
  2. Внесите следующие изменения в свою uploadTransactionData() функцию:

     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()
            }
        }
    }
      

Ответ №2:

Это потому, что Firestore не знает, как сохранить значение: MenuItems

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

или:

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