【Swift】Cloud Firestore로 map형을 취득하는 Tips

수정 (02/14)



두 번째 방법은 FirebaseFirestoreSwift 를 사용하지 않으면 할 수 없다는 것은 자신의 착각이었습니다. 죄송합니다.
현재는, 수정하고 있습니다.

소개



최근 Firestore를 사용한 데모 앱을 만들어 놀고 있습니다.
Firestore에서 지원되는 데이터 유형은 다양하지만, 이번에는 그 중에서도 map 타입의 데이터를 얻는 방법에 대해 썼습니다.
Firestore에서 지원하는 데이터 유형에 대한 자세한 내용은 이 공식 참조를 참조하세요.
htps : // 푹 빠져라. 오, ぇ. 코 m / 드 cs / 푹신 s 잡히다 / 마나게 - data / Data-type s

이번에는 두 가지 방법을 실어 둡니다.

운영 환경


  • Xcode12.4
  • iOS14.4

  • 이번에 취득하는 Firestore의 데이터 & Swift측의 오브젝트



    Firestore의 map형을 취득하는 것으로, Firestore측의 데이터 구조가 있는 편이 알기 쉽다고 생각했으므로, 올려 둡니다.

    ■ Firestore의 map형 데이터 모델


    ■ Swift측의 오브젝트(구조체)

    Order.swift
    struct Order: Codable {
        let id: String
        let orderNo: Int
        let imageName: String
        let name: String
        let price: Int
        let isWasabi: Bool
        var isOrderComplete: Bool
    }
    

    [String : Any]에서 직접 인스턴스를 생성하는 방법


    func fetchOrderMap_A() {
        db.collection("ordering").document("01").getDocument { (_document, _error) in
            guard _error == nil else {
                print("Firestoreからエラーを受け取りました。")
                return
            }
            if let document = _document, document.exists {
    
                // document.data()は、[String : Any]になる
                let mapData = document.data() ?? [:]
    
                print(mapData)  // ※補足参照
    
                var orderList: [Order] = []
                // データを1件ずつ抽出
                for (_, data) in mapData {
                    // data(Any型)をdicData([String: Any]型)にキャストする <- Point
                    let dicData = data as! [String : Any]
                    // [String: Any]にキャストされていることを確認
                    print(dicData)
                    // key - value でプロパティ別に値を取り出す。(今回は強制アンラップ。Firestoreのデータ型に合わせてキャストすれば問題なし。)
                    let id = dicData["id"] as! String
                    let orderNo: Int = dicData["orderNo"] as! Int
                    let imageName: String = dicData["imageName"] as! String
                    let name: String = dicData["name"] as! String
                    let price: Int = dicData["price"] as! Int
                    let isWasabi: Bool = dicData["isWasabi"] as! Bool
                    let isOrderComplete: Bool = dicData["isOrderComplete"] as! Bool
                    // インスタンス生成して配列に追加
                    let order = Order(id: id, orderNo: orderNo, imageName: imageName, name: name, price: price, isWasabi: isWasabi, isOrderComplete: isOrderComplete)
                    orderList.append(order)
                }
                // 生成された配列を出力
                print(orderList)
            } else {
                print("ドキュメントが存在しません。")
            }
        }
    }
    

    ※보충


    print(mapData) 런타임의 mapData 내용은 이런 느낌입니다.

    보충
    ["2": {
        id = 002;
        imageName = samon;
        isOrderComplete = 1;
        isWasabi = 1;
        name = "\U30b5\U30fc\U30e2\U30f3";
        orderNo = 2;
        price = 150;
    }, "1": {
        id = 001;
        imageName = "maguro_akami";
        isOrderComplete = 0;
        isWasabi = 0;
        name = "\U8d64\U8eab\U30de\U30b0\U30ed";
        orderNo = 1;
        price = 100;
    }]
    

    위와 같이 key, value의 배열이 되어 있으므로, for文 로 1건씩 처리해 갑니다.
    데이터를 1건 취득할 수 있으면, 취득하고 싶은 데이터부를 [String : Any] 로 캐스트 합니다.
    현재는 name가 유니 코드이지만 문제는 없습니다.

    이러한 스텝을 밟는 것으로, Swift로부터 용이하게 취급할 수 있는 형태로 하고 있습니다.
    여기까지 구현할 수 있으면, 후에는 통상의 JSON 해석등과 하는 방법은 같다고 생각합니다.

    JSON을 씹고 Codable을 사용하는 방법


    func fetchOrderMap_B() {
        db.collection("ordering").document("01").getDocument { (_document, _error) in
            guard _error == nil else {
                print("Firestoreからエラーを受け取りました。")
                return
            }
            if let document = _document, document.exists {
    
                // document.data()は、[String : Any]になる
                let mapData = document.data() ?? [:]
    
                print(mapData)  // ※補足参照
    
                var orderList: [Order] = []
                // データを1件ずつ抽出
                for (_, data) in mapData {
                    // data(Any型)をdicData([String: Any]型)にキャストする <- Point
                    let dicData = data as! [String : Any]
                    // [String: Any]にキャストされていることを確認
                    print(dicData)
                    // ここからJSONを利用する場合の固有処理
                    // JSON へ一時的にキャスト
                    let jsonData = try? JSONSerialization.data(withJSONObject: dicData)
                    // JSON -> Order(Codable)
                    let order = try? JSONDecoder().decode(Order.self, from: jsonData!)
                    if let order = order {
                        orderList.append(order)
                    }
                }
                // 生成された配列を出力
                print(orderList)
            } else {
                print("ドキュメントが存在しません。")
            }
        }
    }
    

    처리 내용은 코멘트에 썼습니다만, 포인트는[String:Any] -> JSON -> Order 와 같이 일시적으로 JSON 를 씹고 나서, 목적의 Order 에 도착해 있는 것입니다.
    자신은 이 방법 밖에 생각하지 않았습니다만, 만약 그 밖에 좋은 방법이 있으면 코멘트에서 가르쳐 주시면 기쁩니다.

    요약



    처음 구현하고 있었을 때는, Firestore로 map형을 취득하면, 아무것도 생각하지 않고 디코드할 수 있다고 생각했습니다만, id = 002; 와 같은 형식으로 값이 돌아왔기 때문에 처음 당황했습니다.

    iOS 앱 개발시 Firestore의 map형을 사용하고 싶은 분은 참고해 주시면 감사하겠습니다.

    좋은 웹페이지 즐겨찾기