Add object property value on particular condition with Ramda

Viewed 562

I am new to Ramda and faced a wall trying to do some Object transformations.

I have one Array of Object, have to map it and transform each Object.

Wanted transformations:

  1. Rename each object keys
  2. Add new key to each Object, based on another key (value depends on condition)

Here it is in code:

Initial array:

const items = [
  {
    id: 1,
    name: 'Name 1',
    factors: [
      { id: 11, name: '11', },
      { id: 12, name: '12', },
      { id: 13, name: '13', },
      { id: 14, name: '14', },
      { id: 15, name: '15', },
    ]
  },
  {
    id: 2,
    name: 'Name 2',
    factors: [],
  },
];

Wanted output array:

const items = [
  {
    key: 1,           // changed property key - already done
    title: 'Name 1',  // changed property key - already done
    factors: [
      { id: 11, name: '11', },
      { id: 12, name: '12', },
      { id: 13, name: '13', },
      { id: 14, name: '14', },
      { id: 15, name: '15', },
    ],
    // add property icon (done)
    // set icon prop based on factors length
    icon: '',        
  },
  {
    key: 2,
    title: 'Name 2',
    // add property icon (done)
    // set icon prop based on factors length
    icon: 'icon'
  },
];

First goal in the above list is completed - I can change property keys of each Object. I also can add a new key to each Object. But I can not set this new property a value based on factors Array.length.

Here is the current code:

const items = [
  {
    id: 1,
    name: 'Name 1',
    factors: [
      { id: 11, name: '11', },
      { id: 12, name: '12', },
      { id: 13, name: '13', },
      { id: 14, name: '14', },
      { id: 15, name: '15', },
    ]
  },
  {
    id: 2,
    name: 'Name 2',
  },
];

const renameKeys = curry((keysMap, obj) =>
  reduce((acc, key) => assoc(keysMap[key] || key, obj[key], acc), {}, keys(obj))
);

const result = map(pipe(
  renameKeys({ id: 'key', name: 'title' }),
  assoc('icon', '---'),  // <= here, set it based on condition - factors.length
), items);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"  crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script> const {curry, assoc, map, pipe, reduce, keys} = R </script>

1 Answers

Ramda has 2 useful methods to transform objects - R.evolve, and R.applySpec. Both methods accept an object with keys, and a transform / create (depending on method) function for each key.

In this case you can use R.applySpec to generate a new object with the desired key names, and values.

const { map, applySpec, prop, pipe, length, ifElse, always } = R;

const selectIcon = pipe(prop('factors'), length, ifElse(isNaN, always('icon1'), always('icon2')))

const fn = map(applySpec({
  key: prop('id'),
  title: prop('name'),
  factors: prop('factors'),
  icon: selectIcon
}));

const items = [{"id":1,"name":"Name 1","factors":[{"id":11,"name":"11"},{"id":12,"name":"12"},{"id":13,"name":"13"},{"id":14,"name":"14"},{"id":15,"name":"15"}]},{"id":2,"name":"Name 2"}];

const result = fn(items);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

The transformer functions can also use R.applySpec to change nested values:

const { map, applySpec, prop, pipe, when, length, ifElse, always } = R;

const selectIcon = pipe(prop('factors'), length, ifElse(isNaN, always('icon1'), always('icon2')))

const keysUpdater = {
  key: prop('id'),
  title: prop('name'),
};

const factorsTransformer = pipe(prop('factors'), when(length, map(applySpec(keysUpdater))));

const fn = map(applySpec({
  ...keysUpdater,
  factors: factorsTransformer,
  icon: selectIcon
}));

const items = [{"id":1,"name":"Name 1","factors":[{"id":11,"name":"11"},{"id":12,"name":"12"},{"id":13,"name":"13"},{"id":14,"name":"14"},{"id":15,"name":"15"}]},{"id":2,"name":"Name 2"}];

const result = fn(items);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Related