Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flat representation through embedded arrays #440

Open
aalbul opened this issue Feb 19, 2016 · 2 comments
Open

Flat representation through embedded arrays #440

aalbul opened this issue Feb 19, 2016 · 2 comments
Labels

Comments

@aalbul
Copy link

aalbul commented Feb 19, 2016

Oh i spend so much time thinking about the title for this issue.
Let me show you an example so it will explain it better.
Let's assume that i have a tree like this:

const tree = new Baobab({
    hosts: [{
        name: 'one',
        deployeds: [{
            name: 'one/deployed1',
            selected: true
        }]
    }, {
        name: 'two',
        deployeds: [{
            name: 'one/deployed2',
            selected: false
        }]
    }, {
        name: 'three',
        deployeds: [{
            name: 'one/deployed3',
            selected: false
        }]
    }]
});

Now, i would like to select a list of all deployed names.
I'm trying to do something like:

console.log(tree.select('hosts', 'deployeds', 'name').get());

But, off course getting "undeffined". The reason, i suppose, is that selector tries to get a field 'deployeds' from of 'hosts' array field and, off course it fails.

Is there are any way to do the query like that? (In an elegant way :))

@Yomguithereal
Copy link
Owner

Hello @aalbul. To do so, you can either rely on raw JavaScript array methods such as .map and .reduce and such but since you will probably need to flatten arrays, you should consider using libraries such as lodash to do so.

Using raw JavaScript

var names = tree.get('hosts')

  // Here we recursively retrieve the name of each deployed
  // This will produce something like the following:
  // [['name1', 'name2'], ['name3', 'name4']]
  .map(function(host) {
    return host.deployeds.map(function(deployed) {
      return deployed.name
    });
  })

  // So now we need to flatten the result to obtain:
  // ['name1', 'name2', 'name3', 'name4']
  .reduce(function(acc, names) {
    return acc.concat(names);
  }, []);

Using lodash

var names = _(tree.get('hosts'))
  .map(function(host) {
    return _.map(host, 'name');
  })
  .flatten()
  .value();

Also know that if this is something you might want to do often in your code, you can also consider creating a monkey that will hold this computed data for you.

@aalbul
Copy link
Author

aalbul commented Feb 22, 2016

Hi @Yomguithereal and thank you for your answer.
For sure that's possible to do with the help of Lodash or just in raw JavaScript.
The problem is that i was trying to achieve that with the help of Baobab to leverage it's caching support.
The idea was to reduce the amount of intermediate result calculation to minimum.
For example, this is how i did it with the help of "Monkey API":

const Baobab = require('baobab');
const _ = require('lodash');
const monkey = Baobab.monkey;

const tree = new Baobab({
    hosts: [{
        name: 'one',
        deployeds: [{
            name: 'one/deployed1',
            selected: true
        }]
    }, {
        name: 'two',
        deployeds: [{
            name: 'one/deployed2',
            selected: false
        }]
    }, {
        name: 'three',
        deployeds: [{
            name: 'one/deployed3',
            selected: false
        }]
    }]
});

tree.set('selectedDeployeds', monkey({
    cursors: {
        hosts: ['hosts']
    },
    get: (data) => {
        console.log('Calculating selected for all hosts.');
        return _.flatten(_.pluck(data.hosts, 'selectedDeployeds'));
    }
}));

tree.select('hosts').map((host) => {
    host.set('selectedDeployeds', monkey({
        cursors: {
            deployeds: _.flatten([host.solvedPath, 'deployeds'])
        },
        get: (data) => {
            console.log('Calculating selected for host', data);
            return _.filter(data.deployeds, (deployed) => deployed.selected === true);
        }
    }))
});

console.log(tree.get('selectedDeployeds'));
tree.select('hosts', 2, 'deployeds', 0).set('selected', true);
console.log(tree.get('selectedDeployeds'));

The output will look like:

/usr/local/bin/node events.js
Calculating selected for all hosts.
Calculating selected for host { deployeds: [ { name: 'one/deployed1', selected: true } ] }
Calculating selected for host { deployeds: [ { name: 'one/deployed2', selected: false } ] }
Calculating selected for host { deployeds: [ { name: 'one/deployed3', selected: false } ] }
[ { name: 'one/deployed1', selected: true } ]
Calculating selected for all hosts.
Calculating selected for host { deployeds: [ { name: 'one/deployed3', selected: true } ] }
[ { name: 'one/deployed1', selected: true },
  { name: 'one/deployed3', selected: true } ]

Process finished with exit code 0

The idea is to settle monkeys on every "host" node so it can cache the results within it and then to settle a monkey within a global object so it will cache results of the host's monkeys.
This means that we can reduce the amount of iterations significantly.

And as you see, It works. However i'm not really happy with implementation:

  1. It's not fluent. (as for me)
  2. I have to manage monkey instances on each of "host" all the time. I mean, when i'm adding "host" to tree, i need to register a monkey for it. Do i need to un-register it BTW? Or it will be garbage collected?
  3. I would better prefer to get a cursor to it and use the caching. It will allow you to make an ad-hock queries instead of creating a separate monkey for every specific case. I see that current implementation does not allow to use cursors to traverse objects inside of arrays. This is something that done intentionally or just not implemented yet?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants