Tutorial: Browsing data

Serverless DatabaseData Structure Browsing data

Before doing any operation on a Webcom database, you need a reference to a node, which provides a pointer to a location or a data node inside your database tree.

Creating a reference to a node is an extremely light-weight operation, so you can create as many as you like without worrying about wasting bandwidth or memory.

Nevertheless, take care of creating only one instance of the object that represents your Webcom application.
Indeed, each instance of application manages its own authentication state and its own websocket to the Webcom back end. Instantiating more than one often lead to unexpected results, it is possible to do so only in some circumstances.

Once a reference to a node acquired, you can use it to write, read and query its associated data using the other Webcom SDK functions.

First take a reference to the serverless database of the specified Webcom application, and then a reference to the root node:

// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const sampleChatDb = app.serverlessDb; // get a reference to the serverless database service
const rootNode = sampleChatDb.rootNode;  // get a reference to the root node

A node reference comes with a couple of methods to easily navigate through the tree-like structure of the data:

relativeNode() method

This method takes the relative path to a child as parameter and returns a reference pointing to this child node.

var usersNode = rootNode.relativeNode("users");

It accepts several path segments separated by slashes ("/"), as well as usual "." and ".." segments to browse relatively within the data tree hierarchy.

var johnNode = rootNode.relativeNode("users/john");
// is equivalent to:
var otherNode = rootNode.relativeNode("users").relativeNode("john");
// and also equivalent to:
var yetAnotherNode = rootNode.relativeNode("users/mary/../john");
parent property

This property returns a reference to the parent node, or null if the reference already points to the root data node.

var parentNode = usersNode.parent;
// 'parentNode' and 'rootNode' now point to the same node.
Examples

Here are several ways of creating a reference that points to the same Webcom data node:

var usersNode = rootNode.relativeNode("users");
var fredNode = usersNode.relativeNode("fred");
// is equivalent to:
var fredNode = rootNode.relativeNode("users/fred");

var messageListNode = fredNode.parent.parent.relativeNode("message_list");
// is equivalent to:
var messageListNode = app.serverlessDb.rootNode.relativeNode("message_list");
// and to:
var messageListNode = fredNode.relativeNode("../../message_list");

Note that the behaviors of the relativeNode method and the parent property differ when applied on the reference pointing to the root data node:

rootNode.relativeNode("..");
// => returns 'rootNode'
rootNode.parent;
// => returns 'null'
In the beginning is the DatasyncManager

In Android, references to data nodes are created by a DatasyncManager instance, which is in turn provided by the Datasync Service itself:

val myApp = WebcomApplication.default // the app defined by the 'webcom.properties' asset file
val manager = myApp.datasyncService.createManager()
Getting nodes with node()

You can get a reference to a data node from a DatasyncManager instance passing its absolute path to the node() method:

val rootNode = manager.node("/") // The initial "/" is optional
val usersNode = manager.node("/users")

or using the / operator, which results in a more concise code:

val rootNode = manager / ""
val usersNode = manager / "users"

The node() method accepts several path segments separated by slashes ("/"), as well as usual "." and ".." segments to browse relatively within the data tree hierarchy:

val johnNode = manager.node("users/john")
// is equivalent to:
val otherNode = manager.node("users/mary/../john")

or:

val johnNode = manager / "users/john"
// is equivalent to:
val otherNode = manager / "users/mary/../john"
Getting nodes with relativeNode()

You can also get a node reference using a path relative to another node reference with the relativeNode() method:

val alsoJohnNode = usersNode.relativeNode("john")
// 'alsoJohnNode' and 'johnNode' now point to the same data node

or using the / operator

val alsoJohnNode = usersNode / "john"
// 'alsoJohnNode' and 'johnNode' now point to the same data node
Getting nodes with parent

The parent property of each reference to a data node returns a reference to its parent node, or null if the reference already points to the root data node:

val parentNode = usersNode.parent
// 'parentNode' and 'rootNode' now point to the same data node
Examples

Here are several ways of creating a reference that points to the same Webcom data node:

val usersNode = manager / "users"
val fredNode = usersNodes / "fred"
// is equivalent to:
val fredNode = manager / "users/fred"
// or:
val fredNode = manager / "users" / "fred"

val messageListNode = fredNode.parent?.parent?.relativeNode("message_list")
// is equivalent to:
val messageListNode = WebcomApplication.default.datasyncService.createManager().node("message_list")
// or:
val messageListNode = fredNode.relativeNode("../../message_list")

Note that the behaviors of the relativeNode() method and the parent property differ when applied on the reference pointing to the root data node:

rootNode.relativeNode("..")
// => returns 'rootNode'
rootNode.parent
// => returns 'null'
WebcomApplication instance

First, you need to take a reference to the Webcom application.

The easiest way to configure it is to add a Webcom property in the Info.plist file of your iOS application as follows:

Key Type Value Description
▼ Webcom Dictionary root key for Webcom parameters
      identifier String samplechat identifier of the Webcom application

Then you can use this pretty shortcut:

let app = Webcom.defaultApplication
DatasyncManager instance

Second, you need to instantiate a DatasyncManager object. It manages a collection of node references and will be specially useful to read data.

let datasyncManager = application.datasyncService.createManager()

Usually, you directly write:

let datasyncManager = Webcom.defaultApplication.datasyncService.createManager()
node(for:) method and / operator

Finally, you get a node reference using its absolute path:

let rootNode = datasyncManager.node(for: "/") // The initial "/" is optional.
let usersNode = datasyncManager.node(for: "/users")

or:

let rootNode = datasyncManager / ""
let usersNode = datasyncManager / "users"

The node(for:) method accepts several path segments separated by slashes ("/"), as well as usual "." and ".." segments to browse relatively within the data tree hierarchy:

let johnNode = datasyncManager.node(for: "users/john")
// is equivalent to:
let otherNode = datasyncManager.node(for: "users/mary/../john")

or:

let johnNode = datasyncManager / "users/john"
// is equivalent to:
let otherNode = datasyncManager / "users/mary/../john"
relativeNode(for:) method and / operator

You can also get a node reference using a path relative to another node reference:

let alsoJohnNode = usersNode?.relativeNode(for: "john")
// 'alsoJohnNode' and 'johnNode' now point to the same node.

or:

let alsoJohnNode = usersNode / "john"
// 'alsoJohnNode' and 'johnNode' now point to the same node.
parent property

Each reference provides a property that returns a reference to its parent node, or nil if the reference already points to the root data node:

let parentNode = usersNode?.parent
// 'parentNode' and 'rootNode' now point to the same node.
Examples

Here are several ways of creating a reference that points to the same Webcom data node:

let usersNode = datasyncManager / "users"
let fredNode = usersNodes / "fred"
// is equivalent to:
let fredNode = datasyncManager / "users/fred"
// or:
let fredNode = datasyncManager / "users" / "fred"

let messageListNode = fredNode?.parent?.parent?.relativeNode(for: "message_list")
// is equivalent to:
let messageListNode = Webcom.defaultApplication.datasyncService.createManager().node(for: "message_list")
// and to:
let messageListNode = fredNode?.relativeNode(for: "../../message_list")

Note that the behaviors of the relativeNode(for:) method and the parent property differ when applied on the reference pointing to the root data node:

rootNode?.relativeNode(for: "..")
// => returns 'rootNode'
rootNode?.parent
// => returns 'nil'

Management of large child counts

In order to work around width limitations, which limit the number of children of data nodes, the relativeNode() method also support special hashed path segments. A hashed segment starts with the hash (or sharp) character (#) and is substituted with a uniformly distributed set of 4 path segments. These sub-segments are automatically built from the 6 first digits of the base64 representation of the SHA-1 of the path segment to hash, followed by the path segment to hash itself:

var hashedNode = rootNode.relativeNode('users/#mary');
// is the same as
var hashedNode = rootNode.relativeNode('users/Vm/Uz/G5/mary');
val hashedNode = parentNode.relativeNode("users/#mary")
// is the same as
val hashedNode = parentNode.relativeNode("users/Vm/Uz/G5/mary")
let hashedNode = parentNode.relativeNode(for: "users/#mary")
// is the same as
let hashedNode = parentNode.relativeNode(for: "users/Vm/Uz/G5/mary")

In this way, a hashed path segment makes it possible to manage up to 68,719,476,736 virtual children (actually 4096 children, which have each 4096 children, which have each 4096 children) for a given data node.
Caution! The overall data attached to such a node with a large number of virtual children is nonetheless submitted to the weight limitations and can generally not be red in one bulk. Instead, each (virtual) child node will have to be read separately.