realm.object
Objects are the main concept within Hivekit. An object usually represents a concrete entity in the physical world, e.g., a delivery rider, a vehicle, an employee, a sensor, or a machine.
Each object is identified by an id and can optionally have a label, a location, and key-value data.
Methods
realm.object.create(id, options)
Creates a new object with the given id and options and returns a confirmation. This will throw an
error if the object already exists. If you wish to "upsert" objects, e.g. create them if they don't
exist or update them if they do, use realm.object.set()
instead.
id
the unique identifier for this object within its realmoptions
object with optionallabel
,location
, anddata
properties- returns
promise
success
const realm = await client.realm.get('bengaluru');
realm.object.create('deliveryRider/3252341', {
label: 'Piyush Patel',
location: {
latitude: 12.975261469643115,
longitude: 77.63622615922132,
speed: 4.5
},
data: {
vehicleCharge: 0.8
}
});
realm.object.get(id)
Returns a promise resolving to the current data of the object
id
the unique identifier for this object within its realm- returns
Promise
that resolves to the object's data
const deliveryRider = await realm.object.get('deliveryRider/3252341');
deliveryRider = {
label: 'Piyush Patel',
location: {
coordinateSystem: '',
latitude: 12.975261469643115,
longitude: 77.63622615922132,
accuracy: 0,
speed: 4.5,
heading: 0,
altitude: 0,
altitudeAccuracy: 0,
time: '2022-10-26T19:43:15.5285419+02:00'
},
data: { vehicleCharge: 0.8 },
connectionStatus: 'disconnected'
}
realm.object.update(id, options)
Updates an existing object. Merges the provided properties and their values into the existing object's datastructure.
id
the unique identifier for this object within its realmoptions
object with optionallabel
,location
, anddata
properties- returns
promise
success
// you can update individual properties
realm.object.update('scooter/a14', {label: 'Scooter (In Use)'});
// send location updates and data values
realm.object.update('scooter/a14', {
location: {
latitude: 12.88543,
longitude: 77.63644,
},
data: {
status: 'busy'
}
})
realm.object.set(id, options)
Updates an Object or creates it if it doesn't exist.
id
the unique identifier for this object within its realmoptions
object with optionallabel
,location
, anddata
properties
set
is a great way to create or update many objects at once. It's the recommended method to use when integrating Hivekit with
high volume data sources or APIs. set
does two things:
- it combines
create
andupdate
into "create if not exists, otherwise update" - it does NOT provide a write confirmation, making firehose style data imports more efficient
// assume a high volume API for air traffic data
airtraffic.on( 'update', planes => {
planes.forEach( plane => {
// we just call set for every plane and leave it to Hivekit to bundle the messages.
// please note that set does not return any write confirmation.
realm.object.set(plane.id, {
label: plane.registrationCode,
location: {
latitude: plane.lat,
longitude: plane.lng,
altitude: plane.alt,
speed: plane.speed,
heading: plane.heading
},
data: {
img: plane.imgUrl,
departureAirport: plane.origin,
targetAirport: plane.destination
}
})
})
})
realm.object.list(options)
Provides a list of objects within the realm. This list can be limited based on specific filter criteria. By default, list
will only return the id
, label
and connectionStatus
of each object - but you can specify additional fields to include in the list options.
options
an object with two optional propertiesoptions.where
an array of attribute selectors, e.g.['type="scooter"', 'charge<0.2']
options.field
an array of fields from within an object's data that will be included in the result. You can also add"location"
and/or"data"
to include the full location and data in the list resultsoptions.shape
a shape data structure. If provided, only objects within this shape will be returned.- returns
Promise
list result
const list = await realmA.object.list({
where: ['type="scooter"'],
field: ['charge'],
// only return objects within this radius
shape: {
// longitude of the circle's center in degree
cx: 8.812937349780645,
// latitude of the circle's center in degree
cy: 54.33334283065705,
// radius of the circle in meter
r: 300
}
});
list = {
'scooter/b14': {
id: 'scooter/b14',
label: 'Scooter B14',
connectionStatus: 'disconnected',
data: { charge: 0.5 }
},
'scooter/b15': {
id: 'scooter/b15',
label: 'Scooter B15',
connectionStatus: 'disconnected',
data: { charge: 0.3 }
}
}
realm.object.delete(id)
Deletes an existing objects
id
the unique identifier for this object within its realm- returns
Promise
success
await myRealm.object.delete('scooter/b14')
Object Subscriptions
realm.object.subscribe(options)
Subscriptions give you realtime update feeds for objects - based on certain criteria. You can get notifications for all objects in a given realm, only objects within a given area, objects withing a roaming geofence around another object, objects with certain attributes etc.
options
is an optional object with the following attributesoptions.where
an array of attribute selectors, e.g.['type="scooter"', 'charge<0.2']
options.executeImmediately
iftrue
, the subscription is triggered immediatly with all objects matching the given criteria. Iffalse
or ommited, the subscription will only notify you once something changes.options.shape
lets you specify a circle, rectangle or polygon that an object needs to reside within in order to trigger the subscription. You can find more details about how to specify shapes here.options.scopeType
andoptions.scopeId
. If you want to subscribe to objects within an existing Area , you can do so by specifying{scopeType: 'area' scopeId: 'your-area-id'}
options.target
a radius around another object. This will create a roaming geofence around an object and notify you as objects enter or leave.options.target.id
the id of the target objectoptions.target.r
the radius in meters around the target object- returns a
Promise
that resolves to a subscription object
The callback for your subscription gets two arguments:
subscription.on('update', (fullState, changes) => {
// do something with the list of objects
});
You can use either of these, depending on your requirements. fullState
gives you a map with objectId->objectData. This might be the right choice if you're using frameworks that perform object tree comparisons, such as React or Vue.
changes
gives you an object with added
, updated
and removed
properties, each containing a map with objectId->objectData. This might be a better choice for cases in which you need to keep a list of visualisations in sync, e.g. Markers on a Google Map.
Basic Subscription
// subscribe to all objects within a realm and get the initial list straight away
subscription = await realm.object.subscribe({ executeImmediately: true });
subscription.on('update', (fullState, changes) => {
// do something with the list of objects
});
// and later, once you are no longer interested in updates
subscription.cancel();
Subscribe to objects based on their attributes
You can select objects based on values in their data
using Attribute Selectors
subscription = await realm.object.subscribe({
where: ['type="scooter"', 'charge>0.5']
});
Subscribe to objects within bounds
Shapes follow Shape Data Notation
// circle
subscription = await realm.object.subscribe({
shape: {
// center X (longitude) of a circle
cx: 52.51660212363485,
// center Y (latitude) of a circle
cy: 13.377692047310838,
// radius in meters
r: 500
}
});
// rectangle x/y notation
subscription = await realm.object.subscribe({
shape: {
// top left corner
x1: 13.377692047310838, y1: 52.51660212363485,
// bottom right corner
x2: 13.463014670056378, y2: 52.512515547246664,
}
});
// rectangle directional notation
subscription = await realm.object.subscribe({
shape: {
west: 13.377692047310838,
north: 52.51660212363485,
east: 13.463014670056378,
south: 52.512515547246664,
}
});
// polygon
subscription = await realm.object.subscribe({
shape: {
points: [
{ x: 52.52395, y: 12.39764 },
{ x: 53.52395, y: 13.39764 },
{ x: 51.52395, y: 14.39764 },
]
}
});
Google Maps - Subscribe to Objects in View
When building end-user apps, it's important to limit the number of object updates you subscribe to. Only subscribing to the objects you actually want to display limits bandwidth and improves app performance. To achieve this, e.g. when working with Google Maps, listen to the map's viewport changing and update your subscription accordingly. (Please find the full code here)[https://github.com/hivekit/hivekit-tutorials-and-examples/blob/main/google-maps-integration/main.js]
var mapSubscriptionUpdateScheduled = false;
const mapSubscription = await realm.object.subscribe({
// google map's getBounds returns data in the east,south,north,west format that
// Hivekit understands
shape: googleMapInstance.getBounds().toJSON()
})
function updateMapSubscription() {
mapSubscriptionUpdateScheduled = false;
mapSubscription.update({
shape: map.getBounds().toJSON()
})
}
googleMapInstance.addListener('bounds_changed', () => {
// this event fires for every frame the user pans or zooms. We don't want to
// update our subscription this frequently, so let's throttle it to max twice a second
if (!mapSubscriptionUpdateScheduled) {
mapSubscriptionUpdateScheduled = true;
setTimeout(updateMapSubscription, 500);
}
});
Limiting subscriptions to an existing area
area = await realm.area.create('districts/kreuzberg', {
label: 'Kreuzberg',
shape: {points: [
{ x: -80.19 ,y: 25.774 },
{ x: -66.118 ,y: 18.466 },
{ x: -64.757 ,y: 32.321 },
//...
]},
data: { color: '#FF00FF'}
})
// subscribe to all delivery riders in Kreuzberg which is an area we've created previously
subscription = await realmA.object.subscribe({
where: ['type="deliveryRider"'],
scopeType: 'area',
scopeId: 'districts/kreuzberg'
});
Roaming Geofences
There are two approaches to roaming Geofence subscriptions. You can specify a radius around another object, or you can create a subscription with a shape and continuously update it. We've already covered moving shapes around in the Google Maps example above. So let's look into "subscription targets":
Say you're building an app that shows you discount codes for shops near you as you stroll through the city:
// Create an object for ourselves
const myId = 'shopper/1423'
await realm.object.create(myId, {
label: 'John Doe',
data: {
type: 'shopper'
}
});
// Create some objects representing shops
await realm.object.create('shop/worldsbestshirts', {
label: 'Worlds Best Shirts',
data: {
type: 'shop',
couponCode: 'abc-123'
}
});
await realm.object.create('shop/jeansandmore', {
label: 'Jeans and more',
data: {
type: 'shop',
couponCode: 'xyz-324'
}
});
// Create a subscription for all shops around your location. This will create a geofence around
// you that moves as your object updates
const subscription = await realm.object.subscribe({
target: {
id: myId,
r: 200 // radius of 200 meters
},
where: ['type="shop"']
})
subscription.on('update', results => {
// results will be a list of all shops, including their location, label and data
for( var shopId in results ) {
console.log(`Hey, there's a code for ${results[shopId].label} near you: ${results[shopId].data.couponCode}`);
}
})
// Use the browser's geolocation API to update your own position
navigator.geolocation.watchPosition(updateMyPosition, err => {console.log('err',err)}, {enableHighAccuracy: true});
function updateMyPosition(pos) {
realm.object.set(myId, {location: pos.coords})
}