Scripting Cookbook
Getting Started
To get started with Server-Side Scripting, please visit the Server Side Scripting page.
Code Samples
Here are some code samples of common data structures to help you get started.
Increment a Property
With this example, we want to keep track of a counter that tracks the number of updates made to a node. After a node
is created, if the user clicks update ten times, we want to have a counter on the node that indicates it has been
updated ten times.
This script should be bound to the p:beforeUpdateNode
policy.
When a node is updated, this method will execute before the transaction commits to the database.
It gives you a chance to modify the node ahead of it being written.
Here, we check for the existence of the counter
property and if it doesn't exist, we initialize it to 0
.
We then increment the counter. The incremented value will be part of the node when it is saved.
function beforeUpdateNode(node)
{
if (!node.data.counter) {
node.data.counter = 0;
}
node.data.counter++;
}
Associate Category Values on Update
With this example, we imagine a scenario where we have an Article that can be assigned zero or more Categories. Each
category has a numeric value that we'd like to sum up before the Article saves so that the Article can store a total
sum of all categories.
Here is a schema we can imagine for Article (my:article
):
{
"type": "object",
"_qname": "my:article",
"properties": {
"title": {
"title": "Title",
"type": "string"
},
"categoryKeys": {
"title": "Category Keys",
"type": "array",
"items": {
"type": "string"
}
},
"totalCategoryValue": {
"title": "Total Category Value",
"type": "number",
"readonly": true
}
}
}
Here is a schema we can imagine for Category (my:category
):
{
"type": "object",
"_qname": "my:category",
"properties": {
"title": {
"title": "Title",
"type": "string"
},
"key": {
"title": "Key",
"type": "string"
},
"value": {
"title": "Value",
"type": "number"
}
}
}
We might have the following categories instantiated:
[{
"title": "Brewers",
"key": "mke",
"value": 1.73
}, {
"title": "Red Sox",
"key": "bos",
"value": 1.41
}, {
"title": "Indians",
"key": "cle",
"value": 1.81
}]
And we might have an article being updated that looks like this:
{
"title": "Future is hopeful for season opener faithfuls",
"categoryKeys": ["mke", "cle"]
}
This script will sum up the value
of each category identified by the Article and will populate thetotalCategoryValue
property for the node.
function beforeUpdateNode(node)
{
// reset to zero
node.data.totalCategoryValue = 0;
// if we have category keys, find the categories they describe and sum up values
if (node.data.categoryKeys && node.data.categoryKeys.length > 0) {
var query = {
"_type": "my:category",
"key": {
"$in": node.data.categoryKeys
}
};
var results = node.branch.query(query);
for (var id in results) {
var categoryValue = results[id].data.value;
if (categoryValue) {
node.data.totalCategoryValue += categoryValue;
}
}
}
}
Associate Category Values on Update (using Relators)
This example builds on the previous one but uses relator properties to model out the categories. We encourage using
relators as they store graph level relationships between your objects for you.
For more information on relator properties, please check out our Relator Property documentation.
Building on the previous example, we might adjust the article to look like this:
{
"type": "object",
"_qname": "my:article",
"properties": {
"title": {
"title": "Title",
"type": "string"
},
"categories": {
"title": "Categories",
"type": "array",
"items": {
"type": "object"
},
"_relator": {
"nodeType": "my:category"
}
},
"totalCategoryValue": {
"title": "Total Category Value",
"type": "number",
"readonly": true
}
}
}
When we create or update our Article, we can now use a picker to pick from Category (my:category
) nodes.
The resulting JSON might look something like this:
{
"title": Future is hopeful for season opener faithfuls",
"categories": [
{
"id": "926c131bbb9814782bb0",
"ref": "node://21a134c5ca2584abb9c8/144fae6eb52299319d43/33dc97ba1db9dd4799ad/926c131bbb9814782bb0",
"title": "Brewers",
"qname": "o:926c131bbb9814782bb0",
"typeQName": "my:category"
},
{
"id": "319d40fa695900c52db9",
"ref": "node://21a134c5ca2584abb9c8/144fae6eb52299319d43/33dc97ba1db9dd4799ad/319d40fa695900c52db9",
"title": "Indians",
"qname": "o:319d40fa695900c52db9",
"typeQName": "my:category"
}
]
}
Where each entry in categories
is a relator property structure.
Here is a modification to the script to work with categories
as a multi-value relator property array.
function beforeUpdateNode(node)
{
// reset to zero
node.data.totalCategoryValue = 0;
// if we have categories, find the related categories and sum up values
if (node.data.categories && node.data.categories.length > 0) {
var query = {
"_doc": {
"$in": []
}
};
for (var i = 0; i < node.data.categories.length; i++) {
query["_doc"]["$in"].push(node.data.categories[i].id);
}
var results = node.branch.query(query);
for (var id in results) {
var categoryValue = results[id].data.value;
if (categoryValue) {
node.data.totalCategoryValue += categoryValue;
}
}
}
}
Copy a property from a Parent Folder
With this example, we ensure that a node will copy a category
property from a parent folder (in a folder hierarchy)
provided that the parent has a category
on it.
This script can be bound to the p:beforeUpdateNode
policy.
The node.parent
property will provide a node reference to the parent. If there is no parent (meaning that the current
node does not have an a:child
parental association pointing to it), then parent will be undefined. Be sure to check
that parent has a value as shown here.
function beforeUpdateNode(node)
{
var parent = node.parent;
if (parent && parent.data.category) {
node.data.category = parent.data.category;
}
}