Association

Type {{#dataTypeArticle objectTypeId}}{{objectTypeId}}{{/dataTypeArticle}}
Datastore Type {{#dataTypeArticle datastoreTypeId}}{{datastoreTypeId}}{{/dataTypeArticle}}
Supports {{#article "security/authorities"}}authorities{{/article}}, {{#article "security/permissions"}}permissions{{/article}}, {{#article "transfer"}}transfer{{/article}}

Associations, on the other hand, do not bear permissions. They are considered structural elements that provide several meanings for the content in a branch:

  • The "linked" relationships between nodes. These relationships can be broken by either party without validating the integrity of either object. An example is a "related items" relationship in a web site. Suppose Product A points to Product B via a linked relationship. If Product B is deleted, the association is also deleted and no harm is done.
  • The "owned" relationships between nodes. These relationships imply that one or both ends of the association require the other end to exist and be valid in order for the entire structure to be valid. An example is a Book with multiple Chapters, where each Chapter has multiple Pages. One way to model this is to think of a Book as owning its Chapters. And each Chapter owns its Pages. If you were to delete a Page, you would invalidate the Chapter (since its now missing pages). And invalidating a Chapter would in turn invalidate the entire Book.
  • Any other kind of relationship that you wish to model. Since associations are nodes, you're free to define custom metadata and custom server-side behaviors for your objects. You might, for example, need to make remote calls to a third-party service to determine the validity of the object model.

Directionality

Each Association defines a source and a target node which are related together via the association. Associations also have a directionality field which defines the direction of the association. This field can have one of two values:

  • directed - the association points from source to target
  • undirected - the association points both from source to target and target to source

An undirected association gives equal merit to the idea that the association points from source to target as from target to source. This allows for a mutual relationship.

An example of a mutual (or undirected) relationship is a married couple. A wife is married to her husband and the husband is also married to his wife. Both are convinced they're in a mutual relationship. Except, of course, when he obsesses over football and forgets to the dishes. Well...

Configuration

Associations are Nodes and so any configuration properties for Nodes also apply to Associations. However, there are a few additional system properties that Associations maintain.

As always, you're free to plug in your own custom properties as you see fit.

The following table presents you the system properties.

Node Properties

Property Type Default Read-Only Description
source text Read-Only The source node ID.
source_type text Read-Only The type (QName) of the source node.
source_changeset text Read-Only The changeset ID of the source node.
target text Read-Only The target node ID.
target_type text Read-Only The type (QName) of the target node.
target_changeset text Read-Only The changeset ID of the target node.
directionality text Read-Only Either directed or undirected.

Create an Association

You can create an arbitrary, untyped relationship between two nodes. If you don't specify the type of relationship, Cloud CMS uses the generic but much-esteemed a:linked association type.

Here's an example of a simple, generic association:

// assume we have two nodes
var sourceNode = ...;
var targetNode = ...;

// create the association
sourceNode.associate(targetNode);

Of course, you're far better off if you give your associations a type. By giving them a type, you add some meaning to the association. You define the type using association type definitions. See the section on Definitions for information on how to do this.

Let's revisit our book example from above. Suppose we have an association type called custom:hasChapter. We can create an association like this:

// assume we have two nodes
var bookNode = ...;
var chapterNode = ...;

// create the association of type "custom:hasChapter"
bookNode.associate(chapterNode, "custom:hasChapter");

What about undirected associations? It's pretty easy. Here is our marriage example from above:

// assume we have two nodes
var mary = ...;
var bob = ...;

// let's marry these kids
// we create an undirected association
mary.associate(bob, "custom:married", true);

Finally, what if you want to create an association to a target node. This is the same operation but looking at from the viewpoint of the target (rather than the source). You can do that like this:

// assume we have two nodes
var mary = ...;
var bob = ...;

// let's marry these kids
// we create an undirected association
bob.associateOf(mary, "custom:married", true);

Update an Association

Associations are simply nodes. We update them in exactly the same way that we update Nodes.

// assume we have an association
var association = ...;

// update some properties
association.set("title", "Rock and roll doggy");
association.update();

Delete an Association

You can delete an association just like you delete a node:

// assume we have two nodes
var sourceNode = ...;
var targetNode = ...;

// unassociate (generic)
sourceNode.unassociate(targetNode);

// or if we want to unassociate matching a type
sourceNode.unassociate(targetNode, "custom:hasChapter");

// or if we want to unassociate matching a type (undirected)
sourceNode.unassociate(targetNode, "custom:married", true);

Or you can simple delete an association just as you would delete a node:

// assume we have an association
var association = ...;

// delete it
association.del();

Read an Association

You can read an association just like you read a Node. For example, you can read the node by its ID or its QName:

// assume we have a branch
var branch = ...;

// assume a node id
var nodeId = "4b5b685c980c10f98beb";

// assume a qname
var qname = "custom:myassociation";

// here we read the association
// remember that associations are nodes
branch.readNode(nodeId).then(function() {
    console.log("Found node: " + this.get("title"));
});

// here we read by QName
// remember that associations are nodes
branch.readNode(qname).then(function() {
    console.log("Found node: " + this.get("title"));
});

List Associations

You can list the associations that connect a specific node. Associations, from the perspective of a node, are considered to be OUTGOING or INCOMING.

Here is an example of retrieving all associations that flow in or out of a node.

// assume we have a node
var node = ...;

node.associations().each(function() {
   console.log("Found an association: " + this.getId());
});

You can specify the association type and the direction that you're seeking. Here is an example that retrieves any INCOMING associations of type "custom:hasChapter".

// assume we have a node
var node = ...;

node.associations({
    "type": "custom:hasChapter",
    "direction": "INCOMING"
}).each(function() {
    console.log("Found an association: " + this.getId());
});

Finally, you can apply pagination to reduce the amount of traffic over the wire and enhance performance.

// assume we have a node
var node = ...;

// define our pagination
var pagination = {
    "limit": 10,
    "skip": 20,
    "sort": {
        "title": -1
    }
};

node.associations({
    "type": "custom:hasChapter",
    "direction": "INCOMING"
}, pagination).each(function() {
    console.log("Found an association: " + this.getId());
});

List Incoming Associations

If you just want to retrieve a list of the incoming associations, you can use this shortcut:

// assume we have a node
var node = ...;

// here is a list of all incoming associations
node.incomingAssociations().each(function() {
    console.log("Found an association: " + this.getId());
});

// here we pass in type and pagination
node.incomingAssociations({
    "type": "custom:hasChapter"
},{
    "limit": 10,
    "skip": 20,
    "sort": {
        "title": -1
    }
}).each(function() {
    console.log("Found an association: " + this.getId());
});

List Outgoing Associations

If you just want to retrieve a list of the outgoing associations, you can use this shortcut:

// assume we have a node
var node = ...;

// here is a list of all incoming associations
node.outgoingAssociations().each(function() {
    console.log("Found an association: " + this.getId());
});

// here we pass in type and pagination
node.outgoingAssociations({
    "type": "custom:hasChapter"
},{
    "limit": 10,
    "skip": 20,
    "sort": {
        "title": -1
    }
}).each(function() {
        console.log("Found an association: " + this.getId());
    });