# Add and manage data
# Basic usage
With just 4 actions (set, patch, insert, delete) you can make changes to your vuex store and everything will automatically stay up to date with your firestore!
There are two ways to use vuex-easy-firestore, in 'collection' or 'doc' mode. You can only choose one because this points to the path you sync your vuex module to:
Collection mode
firestoreRefType: 'collection'
firestorePath
should be a firestore collection- Use when working with multiple documents, all docs will automatically be retrieved and sync when making changes.
eg. when a user has multiple "items" like a to-do list
Doc mode
firestoreRefType: 'doc'
firestorePath
should be a single firestore document- Use when working with a single doc.
eg. the "settings" or "config" of a user.
Whether a vuex module is set to 'doc' or 'collection' mode, will have small changes in the actions you can do, but the syntax is mostly the same.
The sync is fully robust and automatically groups any api calls per 1000 ms. That means, no matter how many patches you make, only one api call per 1000ms will be made for a maximum of 500 changes. You don't have to worry about optimising/limiting your api calls, it's all done automatically! (> 500 changes will be automatically split over 2 api calls) You can also customise this debounce duration to eg. 500 or 2000ms.
If you still are confused how to set up your database structure when it comes to documents vs collections, I highly recommend to check this guide from Firebase itself.
# 'collection' mode
In 'collection' mode, documents that are added to your module will be added in an object under the property you can choose with the statePropName
option.
Example Vuex module:
const myModule = {
firestorePath: 'myDocs',
firestoreRefType: 'collection',
moduleName: 'myModule',
statePropName: 'data',
namespaced: true, // automatically added
}
With the setup above when documents are added they will appear in the state of the module myModule
under the prop called data
.
Then with these 4 actions: set, patch, insert and delete, you can edit single docs of your collection. These actions make sure Firestore will stay in sync.
dispatch('myModule/set', doc)
// 'set' will choose to dispatch either `patch` OR `insert` automatically
dispatch('myModule/patch', doc) // doc needs an 'id' prop
dispatch('myModule/insert', doc)
dispatch('myModule/delete', id)
# Insert example
dispatch('myModule/set', {title: 'Hello Firestore 🔥'})
// or
dispatch('myModule/insert', {title: 'Hello Firestore 🔥'})
- The object above has just one field:
title
- Since there is no
id
field, the object will be inserted as new document - The document will automatically get a new ID
- The document will appear in Vuex like so:
// in the module called "myModule"
state: {
data: {
'abc123': {title: 'Hello Firestore 🔥', id: 'abc123'}
}
}
- The document will also be inserted in Firestore at the firestorePath
myDocs
.
# Patch example
If you specify the id
you can modify any data of existing documents.
const id = 'abc123'
dispatch('myModule/set', {id, title: 'Hello Universe 💫 🛰', newField: 1})
// or
dispatch('myModule/patch', {id, title: 'Hello Universe 💫 🛰', newField: 1})
As you can see in the example above, with the patch
action (or set
with id
field) you can modify and/or add new fields.
You can also patch nested fields like so:
dispatch('myModule/patch', {id, tags: {water: true}})
Any other fields inside tags
will be left alone and only water
will be updated (or added as new prop).
# Delete example
There are two ways to delete things: (1) the whole document or (2) just a field! (A field meaning "a property" of that document)
const id = 'abc123'
// Delete the whole document:
dispatch('myModule/delete', id)
// Delete a field of a document:
dispatch('myModule/delete', `${id}.tags.water`)
// the document looks like:
{
id: 'abc123',
tags: {
fire: true,
water: true, // only `water` will be deleted in this example!
}
}
In the above example you can see that you can delete a field (or property) by passing a string and separate sub-props with .
(See here for more info on deleting fields)
# Auto-generated fields
When working with collections, each document insert or update will automatically receive these fields:
created_at
/updated_at
both use:new Date()
created_by
/updated_by
will automatically fill in the userId
You can disable these fields by adding them to your guard
config. See the related documentation on guard.
# Manually assigning doc IDs
You can, but do not need to, assign doc IDs manually.
Every insert will automatically generate an ID and return a promise resolving in the ID of the doc added to the store and Firestore.
This is how you can use the auto-generated ID:
const id = await dispatch('moduleName/insert', newDoc) // returns id
// mind the await!
When assigning ID's manually the recommended way to do so is:
// assign manually
const id = getters['moduleName/dbRef'].doc().id
const newDoc = {id, /* and other fields */}
dispatch('moduleName/insert', newDoc)
As you can see in the example above, each vuex-easy-firestore module has a getter called dbRef
with the reference of your firestorePath
. So when you add .doc().id
to that reference you will "create" a new ID, just how Firestore would do it. This way you can do whatever you want with the ID before / after the insert.
Please note you can also access the ID (even if you don't manually pass it) in the hooks.
# 'doc' mode
In 'doc' mode all changes will take effect on the single document you have passed in the firestorePath.
You will be able to use these actions:
dispatch('moduleName/set', {name: 'my new name'}) // same as `patch`
dispatch('moduleName/patch', {status: 'awesome'})
// Only the props you pass will be updated.
dispatch('moduleName/delete', 'status') // pass a prop-name
// Only the propName (string) you pass will be deleted
And yes, just like in 'collection' mode, you can pass a prop-name with sub-props like so:
dispatch('moduleName/delete', 'settings.banned')
// the doc looks like:
{
userName: 'Satoshi',
settings: {
showStatus: true,
banned: true, // only `banned` will be deleted from the item!
}
}
# Auto-generated fields
When working with a single doc, your document updates will automatically receive these fields:
updated_at
uses:new Date()
updated_by
will automatically fill in the userId
Just as with 'collection' mode, you can disable these fields by adding them to your guard
config. See the related documentation on guard.
# Batch updates/inserts/deletions
Only for 'collection' mode.
Since Vuex Easy Firestore automatically batches any patch, insert or deletion you make, you do not need a separate action for large batches.
Yet there are separate "batch actions" and the difference between regular actions is:
- batch actions use different hooks that are only called once for the entire batch
patchBatch
is used to update props with the same content to an array of IDs
dispatch('moduleName/insertBatch', docs)
// pass an array of docs
dispatch('moduleName/patchBatch', {doc: {}, ids: []})
// `doc` is an object with the fields to patch, `ids` is an array
dispatch('moduleName/deleteBatch', ids)
// pass an array of ids
All batch actions will return a promise resolving to an array of the edited / added ids.
In case you need to use patchBatch
but have different content for each document you want to update, please use the regular patch
action.
# Duplicating docs
Only for 'collection' mode.
You can duplicate a document really simply by dispatching 'duplicate' and passing the id of the target document. In the example we will add a document and duplicate it afterwards, so we have 2 documents that look exactly like each other.
const newBulbasaur = {id: '001', name: Bulbasaur, types: {grass: true, poison: true}}
dispatch('pokemonBox/insert', newBulbasaur)
// Bulbasaur is added with the id '001'.
// In another part of your app, you can now duplicate this document like so:
dispatch('pokemonBox/duplicate', '001')
You have to pass the doc ID of an existing doc in your 'collection'. The document also has to be loaded in the Vuex module, so you will have to make sure you either (1) added the document locally or (2) retrieved the document from Firestore first.
In our example above we have copied the Bulbasaur document with all its props and added a duplicate doc with a new random ID. The duplicated doc will automatically be added to your Vuex module and synced to Firestore as well.
If you need to know which new ID was generated for the duplicate, you can retrieve it from the action:
const idMap = await dispatch('pokemonBox/duplicate', '001')
// mind the await!
// idMap will look like this:
{'001': dupeId}
// dupeId will be a string with the ID of the duplicate!
In the example above, if Bulbasaur ('001') was duplicated and the new document has random ID '123abc'
the idMap
will be {'001': '123abc'}
.
# Duplicate batch
This is how you duplicate a batch of documents:
const idMap = await dispatch('pokemonBox/duplicateBatch', ['001', '004', '007'])
// idMap will look like this:
{
'001': 'some-random-new-ID-1',
'004': 'some-random-new-ID-2',
'007': 'some-random-new-ID-3',
}
This way you can use the result if you need to do extra things to your duplicated docs and you will know for each ID which new ID was used to make a duplication.