Skip to main content

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 realm
  • options object with optional label, location, and data 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 realm
  • options object with optional label, location, and data 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 realm
  • options object with optional label, location, and data 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 and update 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 properties
  • options.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 results
  • options.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 attributes
  • options.where an array of attribute selectors, e.g. ['type="scooter"', 'charge<0.2']
  • options.executeImmediately if true, the subscription is triggered immediatly with all objects matching the given criteria. If false 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 and options.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 object
  • options.target.r the radius in meters around the target object
  • returns a Promise that resolves to a subscription object
tip

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})
}