- Collection
The Collection class lays at the heart of
firestorter
. It represents a collection in Firestore and its queried data. It is observable so that it can be efficiently linked to a React Component usingmobx-react
'sobserver
pattern.Collection supports three modes of real-time updating:
- "auto" (real-time updating is enabled on demand) (default)
- "on" (real-time updating is permanently turned on)
- "off" (real-time updating is turned off, use
.fetch
explicitly)
The "auto" mode ensures that Collection only communicates with the firestore back-end whever the Collection is actually rendered by a Component. This prevents unneccesary background updates and leads to the best possible performance.
When real-time updates are enabled, data is automatically fetched from Firestore whenever it changes in the back-end (using
onSnapshot
). This enables almost magical instant updates. When data is changed, only those documents are updated that have actually changed. Document objects are re-used where possible, and just their data is updated. The same is true for thedocs
property. If no documents where added, removed, re-ordered, then thedocs
property itself will not change.Alternatively, you can keep real-time updates turned off and fetch manually. This will update the Collection as efficiently as possible. If nothing has changed on the back-end, no new Documents would be created or modified.
- Document
Document represents a document stored in the firestore database. Document is observable so that it can be efficiently linked to for instance a React Component using
mobx-react
'sobserver
pattern. This ensures that a component is only re-rendered when data that is accessed in therender
function has changed.
- initFirestorter(config)
Initializes
firestorter
with the firebase-app.- makeContext()
If you need to use different firestore instances for different collections, or otherwise want to avoid global state, you can instead provide a "context" opton when creating Document and Collection instances.
This function takes the same arguments as initFirestore and returns a context suitable for Document and Collection creation.
- mergeUpdateData(data, fields) ⇒
Object
Helper function which merges data into the source and returns the new object.
- isTimestamp(val) ⇒
Boolean
Checks whether the provided value is a valid Firestore Timestamp or Date.
Use this function in combination with schemas, in order to validate that the field in the document is indeed a timestamp.
The Collection class lays at the heart of firestorter
.
It represents a collection in Firestore and its queried data. It is
observable so that it can be efficiently linked to a React Component
using mobx-react
's observer
pattern.
Collection supports three modes of real-time updating:
- "auto" (real-time updating is enabled on demand) (default)
- "on" (real-time updating is permanently turned on)
- "off" (real-time updating is turned off, use
.fetch
explicitly)
The "auto" mode ensures that Collection only communicates with the firestore back-end whever the Collection is actually rendered by a Component. This prevents unneccesary background updates and leads to the best possible performance.
When real-time updates are enabled, data is automatically fetched
from Firestore whenever it changes in the back-end (using onSnapshot
).
This enables almost magical instant updates. When data is changed,
only those documents are updated that have actually changed. Document
objects are re-used where possible, and just their data is updated.
The same is true for the docs
property. If no documents where
added, removed, re-ordered, then the docs
property itself will not
change.
Alternatively, you can keep real-time updates turned off and fetch manually. This will update the Collection as efficiently as possible. If nothing has changed on the back-end, no new Documents would be created or modified.
Kind: global class
- Collection
- new Collection([source], [options])
- .docs :
Array
- .hasDocs :
boolean
- .ref :
firestore.CollectionReference
|function
- .id :
string
- .path :
string
|function
- .query :
firestore.Query
|function
- .mode :
string
- .isActive :
boolean
- .isLoading :
boolean
- .fetch() ⇒
Promise
- .ready() ⇒
Promise
- .add(data) ⇒
Promise
Param | Type | Description |
---|---|---|
[source] | CollectionSource |
String-path, ref or function that returns a path or ref |
[options] | Object |
Configuration options |
[options.query] | function | Query |
See |
[options.mode] | String |
See |
[options.createDocument] | function |
Factory function for creating documents |
[options.minimizeUpdates] | boolean |
Enables additional algorithms to reduces updates to your app (e.g. when snapshots are received in rapid succession) |
[options.debug] | boolean |
Enables debug logging |
[options.debugName] | String |
Name to use when debug logging is enabled |
Example
import {Collection} from 'firestorter';
// Create a collection using path (preferred)
const col = new Collection('artists/Metallica/albums');
// Create a collection using a reference
const col2 = new Collection(firebase.firestore().collection('todos'));
// Create a collection and permanently start real-time updating
const col2 = new Collection('artists', {
mode: 'on'
});
// Create a collection with a query on it
const col3 = new Collection('artists', {
query: (ref) => ref.orderBy('name', 'asc')
});
Example
// In manual mode, just call `fetch` explicitely
const col = new Collection('albums', {mode: 'off'});
col.fetch().then((collection) => {
collection.docs.forEach((doc) => console.log(doc));
});
// Yo can use the `isLoading` property to see whether a fetch
// is in progress
console.log(col.isLoading);
Array of all the documents that have been fetched from firestore.
Kind: instance property of Collection
Example
collection.docs.forEach((doc) => {
console.log(doc.data);
});
True whenever the docs array is not empty.
Kind: instance property of Collection
Firestore collection reference.
Use this property to get or set the collection reference. When set, a fetch to the new collection is performed.
Alternatively, you can also use path
to change the
reference in more a readable way.
Kind: instance property of Collection
Example
const col = new Collection(firebase.firestore().collection('albums/splinter/tracks'));
...
// Switch to another collection
col.ref = firebase.firestore().collection('albums/americana/tracks');
Id of the Firestore collection (e.g. 'tracks').
To get the full-path of the collection, use path
.
Kind: instance property of Collection
Path of the collection (e.g. 'albums/blackAlbum/tracks').
Use this property to switch to another collection in the back-end. Effectively, it is a more compact and readable way of setting a new ref.
Kind: instance property of Collection
Example
const col = new Collection('artists/Metallica/albums');
...
// Switch to another collection in the back-end
col.path = 'artists/EaglesOfDeathMetal/albums';
Use this property to set any order-by, where,
limit or start/end criteria. When set, that query
is used to retrieve any data. When cleared (undefined
),
the collection reference is used.
The query can be a Function of the form
(firestore.CollectionReference) => firestore.Query | null | undefined
.
Where returning null
will result in an empty collection,
and returning undefined
will revert to using the collection
reference (the entire collection).
If the query function makes use of any observable values then it will be re-run when those values change.
query can be set to a direct Firestore Query
object but this
is an uncommon usage.
Kind: instance property of Collection
Example
const todos = new Collection('todos');
// Sort the collection
todos.query = (ref) => ref.orderBy('text', 'asc');
// Order, filter & limit
todos.query = (ref) => ref.where('finished', '==', false).orderBy('finished', 'asc').limit(20);
// React to changes in observable and force empty collection when required
todos.query = (ref) => authStore.uid ? ref.where('owner', '==', authStore.uid) : null;
// Clear the query, will cause whole collection to be fetched
todos.query = undefined;
Real-time updating mode.
Can be set to any of the following values:
- "auto" (enables real-time updating when the collection is observed)
- "off" (no real-time updating, you need to call fetch explicitly)
- "on" (real-time updating is permanently enabled)
Kind: instance property of Collection
Returns true when the Collection is actively listening for changes in the firestore back-end.
Kind: instance property of Collection
True when new data is being loaded.
Fetches are performed in these cases:
- When real-time updating is started
- When a different
ref
orpath
is set - When a
query
is set or cleared - When
fetch
is explicitely called
Kind: instance property of Collection
Example
const col = new Collection('albums', {mode: 'off'});
console.log(col.isLoading); // false
col.fetch(); // start fetch
console.log(col.isLoading); // true
await col.ready(); // wait for fetch to complete
console.log(col.isLoading); // false
Example
const col = new Collection('albums');
console.log(col.isLoading); // false
const dispose = autorun(() => {
console.log(col.docs); // start observing collection data
});
console.log(col.isLoading); // true
...
dispose(); // stop observing collection data
console.log(col.isLoading); // false
Fetches new data from firestore. Use this to manually fetch
new data when mode
is set to 'off'.
Kind: instance method of Collection
Fulfil: Collection
- This collection
Reject: Error
- Error describing the cause of the problem
Example
const col = new Collection('albums', 'off');
col.fetch().then(({docs}) => {
docs.forEach(doc => console.log(doc));
});
Promise that is resolved when the Collection has finished fetching its (initial) documents.
Use this method to for instance wait for the initial snapshot update to complete, or to wait for fresh data after changing the path/ref.
Kind: instance method of Collection
Example
const col = new Collection('albums', {mode: 'on'});
await col.ready();
console.log('albums: ', col.docs);
Example
const col = new Collection('artists/FooFighters/albums', {mode: 'on'});
await col.ready();
...
// Changing the path causes a new snapshot update
col.path = 'artists/TheOffspring/albums';
await col.ready();
console.log('albums: ', col.docs);
Add a new document to this collection with the specified data, assigning it a document ID automatically.
Kind: instance method of Collection
Fulfil: Document
- The newly created document
Reject: Error
- Error, e.g. a schema validation error or Firestore error
Param | Type | Description |
---|---|---|
data | Object |
JSON data for the new document |
Example
const doc = await collection.add({
finished: false,
text: 'New todo',
options: {
highPrio: true
}
});
console.log(doc.id); // print id of new document
Example
// If you want to create a document with a custom Id, then
// use the Document class instead, like this
const docWithCustomId = new Document('todos/mytodoid');
await docWithCustomId.set({
finished: false,
text: 'New todo',
});
Document represents a document stored in the firestore database.
Document is observable so that it can be efficiently linked to for instance
a React Component using mobx-react
's observer
pattern. This ensures that
a component is only re-rendered when data that is accessed in the render
function has changed.
Kind: global class
- Document
- new Document([source], [options])
- .schema :
function
- .data :
Object
- .hasData :
boolean
- .ref :
firestore.DocumentReference
|function
- .id :
string
- .path :
string
|function
- .mode :
string
- .isActive :
boolean
- .snapshot :
firestore.DocumentSnapshot
- .isLoading :
boolean
- .update(fields) ⇒
Promise
- .set(data, [options]) ⇒
Promise
- .delete() ⇒
Promise
- .fetch() ⇒
Promise
- .ready() ⇒
Promise
Param | Type | Description |
---|---|---|
[source] | DocumentSource |
String-path, ref or function that returns a path or ref |
[options] | Object |
Configuration options |
[options.mode] | String |
See |
[options.schema] | function |
Superstruct schema for data validation |
[options.snapshot] | firestore.DocumentSnapshot |
Initial document snapshot |
[options.snapshotOptions] | firestore.SnapshotOptions |
Options that configure how data is retrieved from a snapshot |
[options.debug] | boolean |
Enables debug logging |
[options.debugName] | String |
Name to use when debug logging is enabled |
Returns the superstruct schema used to validate the document, or undefined.
Kind: instance property of Document
Returns the data inside the firestore document.
Kind: instance property of Document
Example
todos.docs.map((doc) => {
console.log(doc.data);
// {
// finished: false
// text: 'Must do this'
// }
});
True whenever the document has fetched any data.
Kind: instance property of Document
Firestore document reference.
Use this property to get or set the underlying document reference.
Alternatively, you can also use path
to change the
reference in more a readable way.
Kind: instance property of Document
Example
const doc = new Document('albums/splinter');
// Get the DocumentReference for `albums/splinter`
const ref = doc.ref;
// Switch to another document
doc.ref = firebase.firestore().doc('albums/americana');
Id of the firestore document.
To get the full-path of the document, use path
.
Kind: instance property of Document
Path of the document (e.g. 'albums/blackAlbum').
Use this property to switch to another document in the back-end. Effectively, it is a more compact and readable way of setting a new ref.
Kind: instance property of Document
Example
const doc = new Document('artists/Metallica');
...
// Switch to another document in the back-end
doc.path = 'artists/EaglesOfDeathMetal';
// Or, you can use a reactive function to link
// to the contents of another document.
const doc2 = new Document('settings/activeArtist');
doc.path = () => 'artists/' + doc2.data.artistId;
Real-time updating mode.
Can be set to any of the following values:
- "auto" (enables real-time updating when the document becomes observed)
- "off" (no real-time updating, you need to call fetch explicitly)
- "on" (real-time updating is permanently enabled)
Kind: instance property of Document
Returns true when the Document is actively listening for changes in the firestore back-end.
Kind: instance property of Document
Underlying firestore snapshot.
Kind: instance property of Document
True when new data is being loaded.
Loads are performed in these cases:
- When real-time updating is started
- When a different
ref
orpath
is set - When a
query
is set or cleared - When
fetch
is explicitely called
Kind: instance property of Document
Example
const doc = new Document('albums/splinter', {mode: 'off'});
console.log(doc.isLoading); // false
doc.fetch(); // start fetch
console.log(doc.isLoading); // true
await doc.ready(); // wait for fetch to complete
console.log(doc.isLoading); // false
Example
const doc = new Document('albums/splinter');
console.log(doc.isLoading); // false
const dispose = autorun(() => {
console.log(doc.data); // start observing document data
});
console.log(doc.isLoading); // true
...
dispose(); // stop observing document data
console.log(doc.isLoading); // false
Updates one or more fields in the document.
The update will fail if applied to a document that does not exist.
Kind: instance method of Document
Param | Type | Description |
---|---|---|
fields | Object |
Fields to update |
Example
await todoDoc.update({
finished: true,
text: 'O yeah, checked this one off',
foo: {
bar: 10
}
});
Writes to the document.
If the document does not exist yet, it will be created. If you pass options, the provided data can be merged into the existing document.
Kind: instance method of Document
Param | Type | Description |
---|---|---|
data | Object |
An object of the fields and values for the document |
[options] | Object |
Set behaviour options |
[options.merge] | Boolean |
Set to |
Example
const todo = new Document('todos/mynewtodo');
await todo.set({
finished: false,
text: 'this is awesome'
});
Deletes the document in Firestore.
Returns a promise that resolves once the document has been successfully deleted from the backend (Note that it won't resolve while you're offline).
Kind: instance method of Document
Fetches new data from firestore. Use this to manually fetch
new data when mode
is set to 'off'.
Kind: instance method of Document
Fullfil: Document<T>
This document
Example
const doc = new Document('albums/splinter');
await doc.fetch();
console.log('data: ', doc.data);
Promise that is resolved when the Document has data ready to be consumed.
Use this function to for instance wait for the initial snapshot update to complete, or to wait for fresh data after changing the path/ref.
Kind: instance method of Document
Example
const doc = new Document('albums/splinter', {mode: 'on'});
await doc.ready();
console.log('data: ', doc.data);
Example
const doc = new Document('albums/splinter', {mode: 'on'});
await doc.ready();
...
// Changing the path causes a new snapshot update
doc.path = 'albums/americana';
await doc.ready();
console.log('data: ', doc.data);
Mode : Mode
Real-time updating mode.
Initializes firestorter
with the firebase-app.
Kind: global function
Param | Type | Description |
---|---|---|
config | Object |
Configuration options |
config.firebase | Firebase |
Firebase reference |
[config.app] | String | FirebaseApp |
FirebaseApp to use (when omitted the default app is used) |
Example
import firebase from 'firebase';
import 'firebase/firestore';
import {initFirestorter, Collection, Document} from 'firestorter';
// Initialize firebase app
firebase.initializeApp({...});
// Initialize `firestorter`
initFirestorter({firebase: firebase});
// Create collection or document
const albums = new Collection('artists/Metallica/albums');
...
const album = new Document('artists/Metallica/albums/BlackAlbum');
...
If you need to use different firestore instances for different collections, or otherwise want to avoid global state, you can instead provide a "context" opton when creating Document and Collection instances.
This function takes the same arguments as initFirestore and returns a context suitable for Document and Collection creation.
Kind: global function
Example
import firebase from 'firebase';
import 'firebase/firestore'
import * as firetest from '@firebase/testing'
import {makeContext, Collection, Document} from "firestorter"
function makeTestContext(fbtestArgs) {
const app = firetest.initializeTestApp(fbtestArgs)
return makeContext({
firestore,
app,
})
}
// create collection or document without global state
test('collection and document using different apps', () => {
const context1 = makeTestContext({ projectId: 'foo' })
const context2 = makeTestContext({ projectId: 'bar' })
// Create collection or document
const albums = new Collection('artists/Metallica/albums', {context: context1});
...
const album = new Document('artists/Metallica/albums/BlackAlbum', {context: context2});
...
})
Helper function which merges data into the source and returns the new object.
Kind: global function
Returns: Object
-
Result
Param | Type | Description |
---|---|---|
data | Object |
JSON data |
fields | Object |
JSON data that supports field-paths |
Checks whether the provided value is a valid Firestore Timestamp or Date.
Use this function in combination with schemas, in order to validate that the field in the document is indeed a timestamp.
Kind: global function
Param | Type | Description |
---|---|---|
val | Object |
Value to check |
Example
import { isTimestamp } from 'firestorter';
const TaskSchema = struct({
name: 'string',
startDate: isTimestamp,
duration: 'number'
});
const doc = new Document('tasks/mytask', {
schema: TaskSchema
});
await doc.fetch();
console.log('startDate: ', doc.data.startDate.toDate());