Realtime Database and Firestore parser

Overview

Columbina's FirebaseParser

Easy parsing for Firebase Realtime Database or Firestore.

Dealing with Firebase documents might be tricky. Since it doesn't support arrays, we usually have to run through keys and values and manually extract them into our models.

FirebaseParser allows you to parse a Firebase json without hustle, only by using your own models.

How to use it

Parsing root composed of an array of objects

From a given Firebase document in which each root key is "dynamic", meaning that they vary instead of being fixed strings, you can use the FirebaseDynamicRoot object.

For instance, for the following json, which represents an array of Chats:

{
    "one": {
      "title": "Historical Tech Pioneers",
      "lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
      "timestamp": 1459361875666
    },
    "two": {
      "title": "Historical Tech Pioneers",
      "lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
      "timestamp": 1459361875666
    }
}

You can parse it like this:

struct Chat: Codable {
    let title: String
    let lastMessage: String
    let timestamp: Date
}
...
messagesReference.observe(DataEventType.value, with: { [weak self] snapshot in
    guard let dictionary = snapshot.value as? NSDictionary else { return }
    
    let data = try? JSONSerialization.data(withJSONObject: dictionary, options: []),
    
    if let decoded = try? JSONDecoder().decode(FirebaseDynamicRoot<Chat>.self, from: data) {
        let chats = decoded.map {
            let key = $0.key
            let value = $0.value
            
            return Chat(title: value.title,
                        lastMessage: value.lastMessage,
                        timestamp: value.timestamp)
        }
    }
})

You can access FirebaseDynamicRoot's items in two ways: like an array or like a dictionary.

If you access the dynamic root as an array, you will have access to two properties, key and value:

let decoded = try! JSONDecoder().decode(FirebaseDynamicRoot<Chat>.self, from: data)

print(decoded[0].key)
// one

print(decoded[0].value)
// Chat(title: "Historical Tech Pioneers", lastMessage: "ghopper: Relay malfunction found. Cause: moth.", timestamp: 48246-05-04 10:47:46 +0000)

When you access the dynamic root as a dictionary, you get the value right away:

let decoded = try! JSONDecoder().decode(FirebaseDynamicRoot<Chat>.self, from: data)

print(decoded["one"])
// Chat(title: "Historical Tech Pioneers", lastMessage: "ghopper: Relay malfunction found. Cause: moth.", timestamp: 48246-05-04 10:47:46 +0000)

Be mindful that the access time of using it as a dictionary is O(n), since it's internally stored as an array. Accessing the dynamic root is more performant if accessed like an array, which is O(1).

Parsing root with fixed keys, composed of an array of objects

Take this json example from Firebase:

{
  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
      "timestamp": 1459361875666
    },
    "two": {
      "title": "...",
      "lastMessage": "...",
      "timestamp": ...
    }
  },
  "members": {
    "one": {
      "ghopper": true,
      "alovelace": true,
      "eclarke": true
    }
  },
  "messages": {
    "one": {
      "m1": {
        "name": "eclarke",
        "message": "The relay seems to be malfunctioning.",
        "timestamp": 1459361875337
      }
    },
    "two": {
      "m2": {
        "name": "...",
        "message": "...",
        "timestamp": ...
      }
    }
  }
}

The main difference in this example, is that its root has fixed keys, instead of dynamic ones. In addition to that, each fixed key has dynamic children. In other words, each key has what we would consider an array of objects in a tipical json.

Take Chats for instance. The root key is a fixed chats, which holds dynamic keys that could be interpreted as an array of chat objects, where each key is a chat identifier. In this situation, we can define our chat object as a DynamicChildrenArray.

That's how we can parse it:

struct Chat: Codable {
    let title: String
    let lastMessage: String
    let timestamp: Date
}

struct Root: Codable {
    let chats: DynamicChildrenArray
   
}
  
chatsReference.observe(DataEventType.value, with: { [weak self] snapshot in
    guard let dictionary = snapshot.value as? NSDictionary else { return }
    
    let data = try? JSONSerialization.data(withJSONObject: dictionary, options: []),
    
    let decoded = try! JSONDecoder().decode(Root<Chat>.self, from: data)

    let chatOne = decoded.chats[0]
    
    print(chatOne.key)
    // one
    
    print(chatOne.value)
    // Chat(title: "Historical Tech Pioneers", lastMessage: "ghopper: Relay malfunction found. Cause: moth.", timestamp: 48246-05-04 10:47:46 +0000)
})

Alternatively, you can directly access the value by using the key:

let decoded = try! JSONDecoder().decode(Root<Chat>.self, from: data)

let chatOneValue = decoded.chats["one"]

print(chatOneValue)
// Chat(title: "Historical Tech Pioneers", lastMessage: "ghopper: Relay malfunction found. Cause: moth.", timestamp: 48246-05-04 10:47:46 +0000)

Parsing nested objects

Following the same principle, we can parse nested dynamic keys like the messages object as simple as that:

struct Message: Codable {
    let name: String
    let message: String
    let timestamp: Date
}

struct Root: Codable {
    ...
    let messages: DynamicChildrenArray
   
    >
}

   
  

Then:

let decoded = try! JSONDecoder().decode(Root<Chat>.self, from: data)

let m1 = decoded.messages[0].value[0]

print(m1.key)
// m1

print(m1.value)
// Message(name: "eclarke", message: "The relay seems to be malfunctioning.", timestamp: 48246-05-04 10:42:17 +0000)

Or accessing the keys:

let decoded = try! JSONDecoder().decode(Root<Chat>.self, from: data)

let m1Value = result.messages["one"]!["m1"]!

print(m1Value)
// Message(name: "eclarke", message: "The relay seems to be malfunctioning.", timestamp: 48246-05-04 10:42:17 +0000)
You might also like...
An iOS app that visually clones Spotify's app and consumes the official Spotify's Web API to show(and play) songs, podcasts, artists and more.
An iOS app that visually clones Spotify's app and consumes the official Spotify's Web API to show(and play) songs, podcasts, artists and more.

SpotifyClone An iOS app that visually clones Spotify's app and consumes the official Spotify's Web API to show(and play) songs, podcasts, artists and

This To-Do app was developed using Swift and SwiftUI and works on iOS, MacOS (Apple Silicon) and WatchOS. The tasks are kept on storage even when the app is restarted.

ToDo-SwiftUI This app has a lot of sentimental value for me, given that it helped me a lot to understand the process of doing an iOS app and became th

KHabit an open source, pure and minimalistic app which helps you maintain productive habits, and nothing more.

an open source, pure and minimalistic app which helps you maintain productive habits, and nothing more. The app is completely open source, it does not contain in-app or ads, and does not track the user in any way.

iOS app that detects LaTeX symbols from drawings. Built using PencilKit, SwiftUI, Combine and CoreML for iOS 14 and macOS 11.

DeTeXt Finding the symbol you want to use in LaTeX can be hard since you can't memorize all the possible commands and packages for every symbol you mi

an open source, pure and minimalistic app which helps you maintain productive habits, and nothing more.

KHabit an open source, pure and minimalistic app which helps you maintain productive habits, and nothing more. The app is completely open source, it d

๐ŸŽฎ Favorite your games filter and see the upcoming games and ! Swift + Combine = ๐Ÿ’œ Hacktoberfest ๐ŸŽƒ ๐Ÿ‘พ
๐ŸŽฎ Favorite your games filter and see the upcoming games and ! Swift + Combine = ๐Ÿ’œ Hacktoberfest ๐ŸŽƒ ๐Ÿ‘พ

โœจ Revill is App to list games and search best games โœจ Design in Swift UI + Combine โœจ The idea is develop this app in Hacktober Fest Expected To Do Des

Native and encrypted password manager for iOS and macOS.
Native and encrypted password manager for iOS and macOS.

Open Sesame Native and encrypted password manager for iOS and macOS. What is it? OpenSesame is a free and powerful password manager that lets you mana

SwiftUI iOS Widget and WatchOS app that randomly shows a word of the day with description and example.
SwiftUI iOS Widget and WatchOS app that randomly shows a word of the day with description and example.

Word Of The Day iOS Widget and WatchOS app made in SwiftUI that displays a random word of the day with description and example of usuage. Requirements

A SwiftUI implementation of React Hooks. Enhances reusability of stateful logic and gives state and lifecycle to function view.

SwiftUI Hooks A SwiftUI implementation of React Hooks. Enhances reusability of stateful logic and gives state and lifecycle to function view. Introduc

Releases(0.0.2)
  • 0.0.2(Apr 24, 2022)

    Fix parsing children with different structures using DynamicChildrenArray. Now the parser will still iterate through the other elements even if one could not be parsed.

    Full Changelog: https://github.com/Columbina/FirebaseParser/compare/0.0.1...0.0.2

    Source code(tar.gz)
    Source code(zip)
  • 0.0.1(Feb 20, 2022)

    This is a pre-release of FirebaseParser. This library allows parsing of complex structures from Firebase, but there is still some work and testing to be done, so take that into consideration.

    Full Changelog: https://github.com/Columbina/FirebaseParser/commits/0.0.1

    Source code(tar.gz)
    Source code(zip)
Owner
Columbina
Columbina
Firebase Cloud Firestore support library for iOS. ๐Ÿงข

?? Ballcap-iOS Ballcap is a database schema design framework for Cloud Firestore. Why Ballcap Cloud Firestore is a great schema-less and flexible data

1amageek 229 Jan 2, 2023
Aplikasi iOS Advanced Level To Do List dengan Firebase Auth, SwiftUI, MVVM Design Pattern, dan Firebase Firestore

Aplikasi Tasker adalah aplikasi iOS To Do List yang dibuat menggunakan Autentikasi Firebase / Firestore dan MVVM Design Pattern.

DK 10 Oct 17, 2022
Aplikasi iOS Simulasi CRUD Stok Barang dengan SwiftUI, Firebase CLI & Firestore

iStockery Aplikasi iStockery adalah aplikasi stok inventory berbasis iOS yang dibuat menggunakan Firebase (Firestore) secara Local dengan fitur CRUD d

DK 7 Aug 1, 2022
Swift UIKit E-Commerce (UgurShopping) No StoryBoard Firebase, FireStore, FirebaseAuth, KingFisher, SwiftEntryKit, ProgressHud, Alamofire UICollectionViewCompositionalLayout, NotificationCenter

Swift UIKit E-Commerce (UgurShopping) No StoryBoard Firebase, FireStore, FirebaseAuth, KingFisher, SwiftEntryKit, ProgressHud, Alamofire UICollectionViewCompositionalLayout, NotificationCenter

Ugur Hamzaoglu 2 Oct 16, 2022
SwiftUI Jam 2021 - iPad Realtime Calculator

SwiftUI Jam 2021 - iPad Realtime Calculator A SwiftUI iPad calculator with realtime activity Features Addition, Subtraction, Multiplication, Division

Joel Sereno 3 Jan 13, 2022
Realtime feed of ERC721 transfers

Building Notes As a quick hack for handling secrets (like API keys), I just put

PJ Gray 1 Jan 28, 2022
Movie Database app made with SwiftUI and UIKit

HW4_DogukaanKilicarslan Movie Data Base App made with SwiftUI Movie Database app made with SwiftUI Preview Movie Data Base App : Star Wars Characters

null 1 Oct 20, 2021
SwiftUI movies list using The Movie Database (TMDB) API

MyMoviesList About MyMovieList is an application that uses The Movie Database (TMDB) API and is built with SwiftUI. It demo of some SwiftUI (& Combine

Arnaud 1 Dec 5, 2021
In this mini app covered the concepts like basics of SwiftUI and Navigations and Animations and List with CRUD functions and MVVM and App Launch and App icons adding and also applied persistence using UserDefaults Concept.

TodoList In this application used the concepts from the beginner level project of SwiftUI_Evolve_1 The following concepts covered in this mini app Swi

Sivaram Yadav 2 Dec 4, 2021
Mahmoud-Abdelwahab 5 Nov 23, 2022