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.
idthe unique identifier for this object within its realmoptionsobject with optionallabel,location, anddataproperties- returns
promisesuccess
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
idthe unique identifier for this object within its realm- returns
Promisethat 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.
idthe unique identifier for this object within its realmoptionsobject with optionallabel,location, anddataproperties- returns
promisesuccess
// 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.
idthe unique identifier for this object within its realmoptionsobject with optionallabel,location, anddataproperties
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
createandupdateinto "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.
optionsan object with two optional propertiesoptions.wherean array of attribute selectors, e.g.['type="scooter"', 'charge<0.2']options.fieldan 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.shapea shape data structure. If provided, only objects within this shape will be returned.- returns
Promiselist 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
idthe unique identifier for this object within its realm- returns
Promisesuccess
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.
optionsis an optional object with the following attributesoptions.wherean array of attribute selectors, e.g.['type="scooter"', 'charge<0.2']options.executeImmediatelyiftrue, the subscription is triggered immediatly with all objects matching the given criteria. Iffalseor ommited, the subscription will only notify you once something changes.options.shapelets 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.scopeTypeandoptions.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.targeta radius around another object. This will create a roaming geofence around an object and notify you as objects enter or leave.options.target.idthe id of the target objectoptions.target.rthe radius in meters around the target object- returns a
Promisethat 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})
}