Records are the documents in deepstreamHub's realtime data-store. They are atomic bits of JSON data that can be manipulated and observed. Any change to a record is instantly synced across all connected clients.
Using records
Records are requested using client.record.getRecord(name)
. If a record with the specified name doesn't exist yet, it will be created on the fly. If you just want to check if a record exists without creating it, you can use client.record.has(name, callback)
.
Records have set()
and get()
methods to interact with their data and subscribe()
to inform you about updates. Here's what that would look like in action:
// Client A: Hungry customer sees her pizza delivery approach on map
const driver = client.record.getRecord('driver/jack')
driver.subscribe('coords', updateMapPointer)
// Client B: Delivery driver's smartphone feeds position into record
const driver = client.record.getRecord('driver/jack')
navigator.geolocation.watchPosition(position => {
driver.set('coords', position.coords)
})
Paths
get()
, set()
and subscribe()
can be used to get the entire record's data, but also support "paths". Paths let you access sub-parts of your record's data using JSON notation, e.g. pets[1].fur.color
. If a value for a path that doesn't exist yet is set, the path will be created on the fly.
Record lifecycle
When calling client.record.getRecord()
, one of three things can happen:
-
If the record doesn't exist on the client or the platform yet, it will be created. The initial data of a newly created record is an empty object
{}
. -
If the record exists on the platform, but hasn't been loaded onto the client yet, it will be retrieved.
-
If the record is already loaded on the client, its instance will be returned.
Independent of whether the record has been loaded yet, getRecord()
will return a record instance straight away. You can already start setting values or subscribing to updates at this point, however get()
calls might return null
.
To ensure a record is fully loaded use the whenReady(callback)
method. Please note: This method will execute synchronously when the record is already available or asynchronously if its still being loaded. Alternatively you can also check the record's isReady
flag or subscribe to its "ready"
event.
Discarding Records
To inform the server that you're no longer interested in updates for a record, call discard()
. Discard calls are aggregated, meaning that if a record was requested in three different places using getRecord()
, it also needs to be discarded three times in order for the server to be notified.
Deleting Records
Records can be deleted using delete()
. Deleting also discards the record. Whenever a record is deleted by one client, the same record on all other clients will emit a delete
event.
Unsubscribe, Discard and Delete - what's the difference?
unsubscribe()
removes an existing subscription to updates to a record or path. This is purely a client side operation and doesn't notify the platform.
discard()
tells the platform that you're no longer interested in receiving updates for the record.
delete()
irreversibly deletes the record from the database and cache and notifies all backend processes and clients of the deletion.
Getting a snapshot
If you just require a static one-off view into a record's data, but not bother with the entire lifecycle you can also use client.record.snapshot(name, callback)
Naming records
Each record is identified by a name that needs to be unique across the entire system. So what does a great recordname look like? Something like this:
const book = client.record.getRecord('book/iq6auu7d-p9i1vz3q0yi')
This name consists of different parts: book
is the category of the record - this is useful when it comes to automatically arrange records into collections or search through them. iq6auu7d-p9i1vz3q0yi
is a unique id. Unique ids can be generated on the client using client.getUid()
. They consist of a base64 encoded millisecond timestamp and a random string. UIDs are a common concept in distributed systems as they eliminate the need for a centralized, incremental id.
Can't unique id's clash?
Theoretically: yes. But the chances for two ids that were generated within the exact same millisecond to be the same are 1:1x10^16 - or one to 10 quadrillion - which is considered an acceptable risk.
Can I use more descriptive record names?
Absolutely, any string can be used as a record name. But you need to be certain that the string never changes. This is the case for many institutional usecases that are already based on unique ids. If you're building a stock trading platform, it's perfectly fine to name your record for Microsoft's stock stock/msft
. If you however name your user-entry user/lisamiller
and Lisa changes her lastname, you'll have a problem.
Making the username part of the record name
Many permission-strategies in deepstreamHub are based on record, event or rpc-names and the data they contain. To make sure that only johndoe
can change his settings, you would call your record settings/johndoe
and specify an associated Valve rule:
record:
settings/$username:
write: "$username === user.id"
Video Demo
If you would like to learn more have a look at Yasser Fadl, explaining more in detail about records in deepstreamHub.