Monster. Data

In this namespace you will find classes and methods for handling data.

Author
  • schukai GmbH

Classes

Datasource

The datasource class encapsulates the access to data objects.

Pathfinder
Creates a new instance of the constructor.
Pipe
Transformer

Namespaces

Datasource
Namespace for all datasource related functions.

Members

(static, constant) PARENT :string

Type:
  • string

Methods

(static) buildMap(subject, selector, valueTemplateopt, keyTemplateopt, filteropt) → {*}

Maps can be easily created from data objects with the help of the function buildMap().

Maps can be easily created from data objects with the help of the function buildMap().

The path can be specified as either a simple definition a.b.c or a template ${a.b.c}. Key and value can be either a definition or a template. The key does not have to be defined. The templates determine the appearance of the keys and the value of the map. Either a single value id can be taken or a composite key ${id} ${name} can be used.

If you want to access values of the parent data set, you have to use the ^ character, for example ${id} ${^.name}.

Parameters:
NameTypeAttributesDescription
subject*

The data object from which the map will be created

selectorstring | Monster.Data~exampleSelectorCallback

The path to the data object, or a callback that returns a map.

valueTemplatestring<optional>

A template for the value of the map.

keyTemplatestring<optional>

A template for the key of the map.

filterMonster.Data~exampleFilterCallback<optional>

A callback function to filter out values.

Throws:
    • If the value is neither a string nor a function.
    Type
    TypeError
    • If the selector callback does not return a map.
    Type
    TypeError
Returns:
  • The created map.
Type: 
*
Example
import {buildMap} from '@schukai/monster/source/data/buildmap.mjs';
// a typical data structure as reported by an api

let map;
let obj = {
    "data": [
        {
            "id": 10,
            "name": "Cassandra",
            "address": {
                "street": "493-4105 Vulputate Street",
                "city": "Saumur",
                "zip": "52628"
            }
        },
        {
            "id": 20,
            "name": "Holly",
            "address": {
                "street": "1762 Eget Rd.",
                "city": "Schwalbach",
                "zip": "952340"
            }
        },
        {
            "id": 30,
            "name": "Guy",
            "address": {
                "street": "957-388 Sollicitudin Avenue",
                "city": "Panchià",
                "zip": "420729"
            }
        }
    ]
};

// The function is passed this data structure and with the help of the selector `'data.*'` the data to be considered are selected.
// The key is given by a simple definition `'id'` and the value is given by a template `'${name} (${address.zip} ${address.city})'`.
map = buildMap(obj, 'data.*', '${name} (${address.zip} ${address.city})', 'id');
console.log(map);

// ↦ Map(3) {
//  '10' => 'Cassandra (52628 Saumur)',
//  '20' => 'Holly (952340 Schwalbach)',
//  '30' => 'Guy (420729 Panchià)'
// }

// If no key is specified, the key from the selection, here the array index, is taken.
map = buildMap(obj, 'data.*', '${name} (${address.zip} ${address.city})');
console.log(map);

// ↦ Map(3) {
//  '0' => 'Cassandra (52628 Saumur)',
//  '1' => 'Holly (952340 Schwalbach)',
//  '2' => 'Guy (420729 Panchià)'
// }

// a filter (function(value, key) {}) can be specified to accept only defined entries.
map = buildMap(obj, 'data.*', '${name} (${address.zip} ${address.city})', 'id', function (value, key) {
    return (value['id'] >= 20) ? true : false
});
console.log(map);

// ↦ Map(2) {
//  20 => 'Holly (952340 Schwalbach)',
//  30 => 'Guy (420729 Panchià)'
// }

(static) buildTree(subject, selector, idKey, parentIDKey, optionsopt) → {*}

Creates a tree structure from a given subject using a selector and specified ID and parent ID keys.

Creates a tree structure from a given subject using a selector and specified ID and parent ID keys.

The buildTree function is a powerful tool for creating tree-like data structures from plain JavaScript objects. It takes in four required parameters: the subject object that you want to turn into a tree, a selector that identifies which parts of the subject to use when building the tree, and two keys (idKey and parentIDKey) that specify which properties in the subject represent the unique identifiers and parent-child relationships between nodes in the tree.

Optionally, you can also pass in an options object to further configure the behavior of the function, such as specifying which values should be treated as roots of the tree, or providing a custom filter function to only include certain nodes in the final output.

The buildTree function works by first using the assembleParts helper function to extract the relevant parts of the subject based on the selector, and then iterates over the resulting map to create Node objects and organize them into parent-child relationships based on the values of the idKey and parentIDKey properties.

The resulting NodeList represents the tree structure, with each Node object containing the original object data as well as additional metadata about its position in the tree. You can then use the childNodes property of each Node to access its children, or the parent property to access its parent.

Overall, the buildTree function is a flexible and powerful way to transform flat data into hierarchical structures, and can be especially useful in scenarios such as displaying folder structures or visualizing complex data relationships.

Let's say you have an array of data objects representing a file system directory structure, and you want to turn it into a tree-like structure where each node represents a folder or file, and child nodes represent the contents of the folder:

const fileSystem = [
  { id: 'folder1', name: 'Folder 1', type: 'folder', parent: null },
  { id: 'file1', name: 'File 1', type: 'file', parent: 'folder1' },
  { id: 'file2', name: 'File 2', type: 'file', parent: 'folder1' },
  { id: 'subfolder1', name: 'Subfolder 1', type: 'folder', parent: 'folder1' },
  { id: 'file3', name: 'File 3', type: 'file', parent: 'subfolder1' },
  { id: 'file4', name: 'File 4', type: 'file', parent: 'subfolder1' },
  { id: 'subfolder2', name: 'Subfolder 2', type: 'folder', parent: 'folder1' },
  { id: 'file5', name: 'File 5', type: 'file', parent: 'subfolder2' },
  { id: 'file6', name: 'File 6', type: 'file', parent: 'subfolder2' },
  { id: 'folder2', name: 'Folder 2', type: 'folder', parent: null },
  { id: 'file7', name: 'File 7', type: 'file', parent: 'folder2' },
  { id: 'file8', name: 'File 8', type: 'file', parent: 'folder2' },
  { id: 'subfolder3', name: 'Subfolder 3', type: 'folder', parent: 'folder2' },
  { id: 'file9', name: 'File 9', type: 'file', parent: 'subfolder3' },
  { id: 'file10', name: 'File 10', type: 'file', parent: 'subfolder3' },
];

const tree = buildTree(fileSystem, 'id', 'id', 'parent', { rootReferences: [null] });

console.log(tree.toString());

The buildTree function takes in the array of data objects, as well as some configuration options specifying the keys to use for identifying nodes and their parent-child relationships. In this example, we use the id key to identify nodes, and the parent key to specify the parent of each node.

The resulting tree object is a nested tree structure, where each node is an object representing a file or folder, and has child nodes representing its contents. The toString method of the tree object can be used to print out the tree in a readable format:

- Folder 1
  - File 1
  - File 2
  - Subfolder 1
    - File 3
    - File 4
  - Subfolder 2
    - File 5
    - File 6
- Folder 2
  - File 7
  - File 8
  - Subfolder 3
    - File 9
    - File 10
Parameters:
NameTypeAttributesDescription
subject*

The object or array to build the tree from.

selectorstring | Monster.Data~exampleSelectorCallback

Either a string to specify a property of each object to use as a selector, or a selector function to generate a map of objects.

idKeystring

The property key to use as the unique ID of each node.

parentIDKeystring

The property key to use as the parent ID of each node.

optionsobject<optional>

Additional options to modify the function behavior.

Properties
NameTypeAttributesDefaultDescription
rootReferencesArray.<*><optional>
[null, undefined]

An array of values to treat as root references when creating the tree.

filterfunction<optional>

A filter function to apply to each node.

Since
  • 1.26.0
License
  • AGPLv3
Throws:
  • selector is neither a string nor a function.

    Type
    TypeError
  • the selector callback must return a map.

    Type
    TypeError
  • the object has no value for the specified id.

    Type
    Error
Returns:

The resulting tree structure as a NodeList.

Type: 
*

(static) diff(first, second) → {array}

With the diff function you can perform the change of one object to another.

With the diff function you can perform the change of one object to another. The result shows the changes of the second object to the first object.

The operator add means that something has been added to the second object. delete means that something has been deleted from the second object compared to the first object.

Parameters:
NameTypeDescription
first*
second*
Since
  • 1.6.0
License
  • AGPLv3
Returns:
Type: 
array
Example
import {Diff} from '@schukai/monster/source/data/diff.mjs';

// given are two objects x and y.

let x = {
    a: 1,
    b: "Hello!"
}

let y = {
    a: 2,
    c: true
}

// These two objects can be compared with each other.

console.log(Diff(x, y));

// the result is then the following

//
// [
// {
//        operator: 'update',
//        path: [ 'a' ],
//        first: { value: 1, type: 'number' },
//        second: { value: 2, type: 'number' }
//    },
// {
//        operator: 'delete',
//        path: [ 'b' ],
//        first: { value: 'Hello!', type: 'string' }
//    },
// {
//        operator: 'add',
//        path: [ 'c' ],
//        second: { value: true, type: 'boolean' }
//    }
// ]

(static) extend(…args) → {object}

Extend copies all enumerable own properties from one or more source objects to a target object.

Extend copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.

Parameters:
NameTypeAttributesDescription
args<repeatable>
Since
  • 1.10.0
License
  • AGPLv3
Throws:
  • unsupported argument

    Type
    Error
  • type mismatch

    Type
    Error
  • unsupported argument

    Type
    Error
Returns:
Type: 
object

Type Definitions

buildTreeOptions

Type:
  • Object
Properties
NameTypeDefaultDescription
options.rootReferencesarray[null,

undefined] defines the values for elements without parents

options.filterMonster.Data~exampleFilterCallback

filtering of the values

exampleFilterCallback(value, key)

With the help of this filter callback, values can be filtered out.

With the help of this filter callback, values can be filtered out. Only if the filter function returns true, the value is taken for the map.

Parameters:
NameTypeDescription
value*

Value

keystring

Key

exampleSelectorCallback(subject)

Alternatively to a string selector a callback can be specified.

Alternatively to a string selector a callback can be specified. this must return a map.

Parameters:
NameTypeDescription
subject*

subject

Since
  • 1.17.0
License
  • AGPLv3
Returns:

Map

Example
import {buildMap} from '@schukai/monster/source/data/buildmap.mjs';

let obj = {
               "data": [
                   {
                       "id": 10,
                       "name": "Cassandra",
                       "enrichment": {
                           variants: [
                               {
                                   sku: 1, label: "XXS", price: [
                                       {vk: '12.12 €'},
                                       {vk: '12.12 €'}
                                   ]
                               },
                               {
                                   sku: 2, label: "XS", price: [
                                       {vk: '22.12 €'},
                                       {vk: '22.12 €'}
                                   ]
                               },
                               {
                                   sku: 3, label: "S", price: [
                                       {vk: '32.12 €'},
                                       {vk: '32.12 €'}
                                   ]
                               },
                               {
                                   sku: 4, label: "L", price: [
                                       {vk: '42.12 €'},
                                       {vk: '42.12 €'}
                                   ]
                               }
                           ]

                       }
                   },
                   {
                       "id": 20,
                       "name": "Yessey!",
                       "enrichment": {
                           variants: [
                               {
                                   sku: 1, label: "XXS", price: [
                                       {vk: '12.12 €'},
                                       {vk: '12.12 €'}
                                   ]
                               },
                               {
                                   sku: 2, label: "XS", price: [
                                       {vk: '22.12 €'},
                                       {vk: '22.12 €'}
                                   ]
                               },
                               {
                                   sku: 3, label: "S", price: [
                                       {vk: '32.12 €'},
                                       {vk: '32.12 €'}
                                   ]
                               },
                               {
                                   sku: 4, label: "L", price: [
                                       {vk: '42.12 €'},
                                       {vk: '42.12 €'}
                                   ]
                               }
                           ]

                       }
                   }
               ]
           };

let callback = function (subject) {
               let m = new Map;

               for (const [i, b] of Object.entries(subject.data)) {

                   let key1 = i;

                   for (const [j, c] of Object.entries(b.enrichment.variants)) {
                       let key2 = j;

                       for (const [k, d] of Object.entries(c.price)) {

                           let key3 = k;

                           d.name = b.name;
                           d.label = c.label;
                           d.id = [key1, key2, key3].join('.');

                           m.set(d.id, d);
                       }

                   }
               }
               return m;
           }

let map = buildMap(obj, callback, '${name} ${vk}', '${id}')

// ↦ Map(3) {
//  "0.0.0":"Cassandra 12.12 €",
//  "0.0.1":"Cassandra 12.12 €",
//  "0.1.0":"Cassandra 22.12 €",
//  "0.1.1":"Cassandra 22.12 €",
//  "0.2.0":"Cassandra 32.12 €",
//  "0.2.1":"Cassandra 32.12 €",
//  "0.3.0":"Cassandra 42.12 €",
//  "0.3.1":"Cassandra 42.12 €",
//  "1.0.0":"Yessey! 12.12 €",
//  "1.0.1":"Yessey! 12.12 €",
//  "1.1.0":"Yessey! 22.12 €",
//  "1.1.1":"Yessey! 22.12 €",
//  "1.2.0":"Yessey! 32.12 €",
//  "1.2.1":"Yessey! 32.12 €",
//  "1.3.0":"Yessey! 42.12 €",
//  "1.3.1":"Yessey! 42.12 €"
// }