fiery-data
A library which binds Firestore data to plain arrays and objects and keeps them in sync.
Features
- Documents example
- Collections (stored as array or map) example
- Queries (stored as array or map) example
- Streams (stored as array or map) example
- Pagination example
- Real-time or once example
- Adding, updating, sync, removing, remove field example
- Sub-collections (with cascading deletions!) example
- Return instances of a class example
- Add active record methods (sync, update, remove, clear, getChanges) example
- Control over what properties are sent on save example
- Encode & decode properties example
- Timestamp/Date properties example
- Adding the key and exists to the document example
- Sharing, extending, defining, and global options example
- Callbacks (error, success, missing, remove) example
- Events (update, remove, create, destroy, missing) example
- Custom binding / unbinding example
Related
- fiery-vue: fiery-data for VueJS
- fiery-vuex: fiery-data for Vuex
Contents
Dependencies
- Firebase ^5.0.0
Installation
npm
Installation via npm : npm install fiery-data --save
Examples
JS
// Firebasevar app = firebasevar fs = firebase // FieryData is available through UMD// factory for creating and destroying live datavar $fiery = // get a single documentvar specificTask = // get a live array of documentsvar tasks = // get a live map of documentsvar taskMap = // get the current array of documents, don't update anythingvar tasksOnce = // updatespecificTaskname = 'New name'$fiery // get new (is not saved)var taskUnsaved = $fiery // get new (saved - updates tasks once "saved")var taskSaved = $fiery // remove$fiery // manually stop live data$fiery // no more live data, saving, or deleting. release cached values$fiery
Each object will contain a .uid
property. This helps identify what firestore
database the document is stored in, the collection, and with which options.
TypeScript
A more advanced example with classes, active record, querying, and definitions
// classes are not required, but supported // you can optional define options globallydefine // firebase // a single document, kept up to date // all documents in the collection, live (ordered by most recently edited) // all done tasks, ordered by most recently done // finish this task - which updates all the referencesspecificTask.finish // no more live data, saving, or deleting. release cached values$fiery.destroy
Another advanced example with sub collections (blog with live comments)
// Classes // OptionssetGlobalOptions define // Firestore & Fiery // Functions $fiery.destroy
API
$fiery ( source, options?, name? )
- source
fs.doc ('path/to/doc')
fs.collection ('items')
- options
- name of options passed to
define
- checkout this file to see the available values
- name of options passed to
- name
- necessary when you call
$fiery
multiple times (like as a result of a function with parameters) or if you want to callcreate
orbuild
passing astring
- necessary when you call
- source
$fiery.update ( data, fields? ): Promise<void>
- data
- the data of a document to update
- fields
- optionally you can pass a field name or array of fields to update (as opposed to all)
- data
$fiery.save ( data, fields? ): Promise<void>
- data
- the data of a document to save (update if it exists, set if it does not)
- fields
- optionally you can pass a field name or array of fields to update (as opposed to all)
- data
$fiery.sync ( data, fields? ): Promise<void>
- data
- the data of a document to update. any fields not on the document or specified in fields will be removed
- fields
- optionally you can pass a field name or array of fields to sync. any other fields in the document not specified here are removed
- data
$fiery.remove ( data, excludeSubs? ): Promise<void>
- data
- the data of the document to remove. by default the sub collections specified in the options are removed as well
- excludeSubs
- if you wish, you could only remove the document data and not the sub collections
- data
$fiery.clear ( data, fields ): Promise<void>
- data
- the data of the document to clear values of
- fields
- the fields to remove from the document - or sub collections to remove (if specified in the options)
- data
$fiery.getChanges ( fields?, isEqual? ): Promise<{changed, remote, local}>
- fields
- optionally you can check specific fields for changes, otherwise all are checked
- isEqual
- you can pass your own function which checks two values for equality
- returns
- the promise resolves with an object with
changed
,remote
, andlocal
changed
is either true or falseremote
are the changed saved valueslocal
are the changed unsaved values
- the promise resolves with an object with
- fields
$fiery.pager ( target ): FieryPager
- target
- the collection to paginate
- target
$fiery.ref ( data, sub? ): DocumentReference | CollectionReference
- data
- the data to get the firebase reference of
- sub
- a sub collection of the given data to return
- data
$fiery.create ( target, initial? )
- target
- the collection to add a value to and save
- initial
- the initial values of the data being created
- target
$fiery.createSub ( target, sub, initial? )
- target
- the target which has the sub collection
- sub
- the sub collection to add a value to and save
- initial
- the initial values of the data being created
- target
$fiery.build ( target, initial? )
- target
- the collection to add a value (unsaved)
- initial
- the initial values of the data being built
- target
$fiery.buildSub ( target, sub, initial? )
- target
- the target which has the sub collection
- sub
- the sub collection to add a value (unsaved)
- initial
- the initial values of the data being created
- target
$fiery.free ( target ): void
- stops live data on the target and removes cached values when possible
$fiery.destroy (): void
- calls free on all targets generated with
$fiery (...)
- calls free on all targets generated with
Feature Examples
Documents
// real-time documentsvar settings = var currentUser =
Collections
// real-time arrayvar cars = // real-time map: carMap[id] = carvar carMap =
Queries
// real-time arrayvar currentCars = // a parameterized query that can be invoked any number of times{ var options = cars return // name (searchCars) is required when parameterized} var cars1 = var cars2 = // cars1 === cars2, same array. Using the name ensures one query is no longer listened to - and only the most recent one
Streams
A stream is an ordered collection of documents where the first N are fetched, and any newly created/updated documents that should be placed in the collection
are added. You can look back further in the stream using more
. A use case for
streams are a message channel. When the stream is first loaded N documents are
read. As new messages are created they are added to the beginning of the collection. If the user wishes to see older messages they simply have to call
more
on the stream to load M more. The once
property does not work on streams, they are real-time only.
You MUST have an orderBy clause on the query option and stream
must be true
.
// streams are always real-time, but can be an array or mapvar messages = // 25 are loaded (if that many exist) // load 10 more$fiery // load 20 more$fiery
Pagination
{ var options = cars // required for prev() - orderBys must be in reverse cars // name (searchCars) is required when parameterized return } var cars = // 10 at a timevar pager = $fiery pagernext // next 10 please, returns a promise which resolves when they're fetched // pager.index // which page we're on// pager.hasNext() // typically returns true since we don't really know - unless cars is empty// pager.next() // executes the query again but on the next 10 results. index++// pager.hasPrev() // looks at pager.index to determines if there's a previous page// pager.prev() // executes the query again but on the previous 10 results. index--
Real-time or once
// real-time is default, all you need to do is specify once: true to disable it // array populated oncevar cars = // current user populated oncevar currentUser =
Adding, updating, overwriting, removing
var currentUser = var todos = // name required to get access to sources // COLLECTIONS STORED IN stores{ $fierysourcestodos // OR var savedTodo = $fiery} { $fiery}{ $fiery} // any document can be passed, ex: this.todos[1], this.currentUser{ $fiery} // only fields present on data will exist on sync{ $fiery}{ $fiery // removes sub collections as well $fiery // preserves sub collections}{ $fierycleartodo 'name' // can also specify an array of props/sub collections}
Sub-collections
You can pass the same options to sub, nesting as deep as you want!
var todos = // todos[todoIndex].children[childIndex] { $fiery // OR $fiery // OR var savedChild = $fiery // OR var unsavedChild = $fiery} { $fieryclearparent 'children' // clear the sub collection of all children currently in parent.children}
Return instances of a class
{}Todoprototype = { thisdone = true thisupdated_at = Date thisupdated_by = byUserid } var todos
Active Record
// can be used with type, doesn't have to be {}Todoprototype = { thisdone = true thisupdated_at = Date thisupdated_by = byUserid this // injected } var todos = todositodositodosi var todosCustom = todosCustomitodosCustomi
Save fields
var todos = var todo = todosi $fiery // sends name and done as configured above$fiery // only send this value if it exists$fiery // ignores exclude and include when specified // $fiery.save also takes fields, when you're not sure if your document exists.
Encode & decode properties
var todos =
Timestamp/Date properties
var todos =
Adding key and exists to object
var todos = // must be excluded manually from saving if include is not specified // todos[i].id => a string identifier of the document// todos[i].exists => true or false if the document exists or not
Sharing, extending, defining, and global options
// ==== Sharing ====let Todo = shared: true // necessary for non-global or defined options that are used multiple times include: 'name' 'done' 'done_at' // ==== Extending ====let TodoWithChildren = shared: true extends: Todo sub: children: Todo // ==== Defining ==== // or multiple // ==== Global ==== var comments = // you can pass a named or Shared
Callbacks
var todos =
Events
{}Taskprototype = $ { // I've been updated } $ { // I've been removed from the firestore } $ { // This instance has been created (runs after constructor if one is given) } $ { // This instance is being recycled. It may still exist in the firestore, but // it no longer is referenced by the app } $ { // This document was attempted to retrieved, but it doesn't exist yet } var tasks =
Or you can specify the names of the functions:
var tasks =
Binding and Unbinding
var todos = // will be live updated $fiery // live updates stop