Property Mapping

QName: f:property-mapping

Automates the assignment or mapping of property values from one end of an association to the other. This feature
is added to an association (or an association definition) to set up an automatically maintained mapping of values
from a "from" node to a "to" node.

The feature allows for multiple mappings to be defined. When the defined "from" node is updated, it's property
value is automatically copied or mapped into the "to" node's recipient property.

The recipient "to" property can either be a scalar value of the same type as the "from" property (for example, a string
or a boolean). It can also be an array in which case multiple values will accumulate with the "from" property's
schema type.

This feature is useful for cases where you want to retain a graph structure for traversal-based lookup and referencing
but also wish to have some properties retained on the endpoints of an association.

One sample use case is to best utilize fast query-based lookup that best leverages the underlying power of MongoDB
to take advantage of single-collection indexing. Another use case is simply requirement driven - if you have a case
where content needs to be mastered once but available in multiple places.

Configuration

<thead>
    <tr>
        <th>Property</th>
        <th>Type</th>
        <th>Default</th>
        <th nowrap>Read-Only</th>
        <th>Description</th>
    </tr>
</thead>
<tbody>
    <tr>
        <td>mappings</td>
        <td></td>
        <td></td>
        <td></td>
        <td>
            An array of mapping configurations.  Each element in the array should have the structure:
{
    "from": "",
    "fromProperty": "",
    "toProperty": ""
}
            Where:

            <ul>
                <li><code>from</code> is either <code>target</code> or <code>source</code>.  This defines which end of the association serves as the "from" node.
                <li><code>fromProperty</code> is the name of the property on the "from" node to read from.
                <li><code>toProperty</code> is the name of ht eproperty on the "to" node to write into.
            </ul>
        </td>
    </tr>
</tbody>

Property Mapping Example

Here is an example of a product node, a category node and an association between them whose type has the
f:property-mapping feature. When categories are added, we collect the category values into a
categories property on the product.

The product node might have a definition like this:

{
    "title": "Product",
    "type": "object",
    "_type": "d:type",
    "_qname": "custom:product",
    "properties": {
        "title": {
            "type": "string",
            "title": "Title"
        },
        "sku": {
            "type": "string",
            "title": "SKU"
        },
        "categories": {
            "type": "array",
            "title": "Categories",
            "items": {
                "type": "string"
            }
        }
    }
}

Our product's have titles and skus. In addition, they maintain a categories
array of string values which are category keys. These will be auto-populated by an association.

The category definition can be pretty simple - something like:

{
    "title": "Category",
    "type": "object",
    "_type": "d:type",
    "_qname": "custom:category",
    "properties": {
        "title": {
            "type": "string",
            "title": "Title"
        },
        "category": {
            "type": "string",
            "title": "Category Key"
        }
    }
}

Let's now define a custom:has-category association that links products to categories. We'll bestow it
with the f:property-mapping feature so that the category key will be copied from the category node to the
product node each time a change is made. The mappings property is an array so it is possible to define
multiple mappings. We only use one here.

{
    "title": "Has Category",
    "type": "object",
    "_type": "d:association",
    "_qname": "custom:has-category",
    "mandatoryFeatures": {
        "f:property-mapping": {
            "mappings": [
                {
                    "from": "target",
                    "fromProperty": "category",
                    "toProperty": "categories"
                }
            ]
        }
    }
}

We can now create a product like this:

{
    "_type": "custom:product",
    "title": "Sandwich",
    "sku": "sandwich-10001"
}

And create a category like this:

{
    "_type": "custom:category",
    "title": "Organic",
    "category": "organic"
}

When we link them together with a custom:has-category association, the product node is automatically
updated and will look like this:

{
    "_type": "custom:product",
    "title": "Sandwich",
    "sku": "sandwich-10001",
    "categories": ["organic"]
}

The product node will essentially track changes to the category and the association between itself at the category.
If the association is deleted, the categories property will be updated. Similarly, if the category
is updated to change it's category value, all nodes connected to it via our custom:has-category
association will update to track changes.