0

I'm trying to create an array of payloads using map and forEach on two different data sources. The payloads array should look like this:

const payloads = [{
  accountId: 1,
  tagId: 'tag1',
  notes: 'random note'
}, 
{
  accountId: 1,
  tagId: 'tag2',
  notes: 'random note'
}, 
{
  accountId: 1,
  tagId: 'tag3',
  notes: 'random note'
},
{
  accountId: 2,
  tagId: 'tag1',
  notes: 'random note'
},
...]

I have the following variables:

const ids = [1, 2, 3]
const tags = ['tag1', 'tag2', 'tag3']
const notes = 'random note'

I'd like to create an array of payloads using this data so that each id has a separate payload with a each note.

I've tried doing the following with lodash map and forEach:

import { forEach, map } from 'lodash';

  const payloads = map(ids, id => forEach(tags, tag => {
    return ({
    accountId: id,
    tagId: tag,
    notes: note
  }
  )}));

This is just returning an array of tags. I'm not sure where I'm going wrong, but I don't think I understand chaining correctly. What am I doing wrong here?

Noob
  • 754
  • 3
  • 10
  • 27
  • 1
    You don't need the whole lodash library just for map and foreach functions. You can use built-in Array.prototype.forEach and Array.prototype.map instead. – Virtuoz May 03 '21 at 19:37
  • Related: [Cartesian product of multiple arrays in JavaScript](https://stackoverflow.com/q/12303989) – VLAZ May 03 '21 at 19:37

2 Answers2

1

First, lodash's forEach always returns the input array as it is. So for each map operation, you're conceptually returning tags array without any transformations. The thing you need is another map operator as answered by Henry. But still a nested map would cause nested arrays as well. So instead of your required result, the result would be like

[
    [ {Object}, {Object}, {Object} ],
    [ {Object}, {Object}, {Object} ],
    [ {Object}, {Object}, {Object} ]
]

To deal with the nesting, you need to use Array.prototype.flat on the transformed result.

So your code would look like

const ids = [1, 2, 3]
const tags = ['tag1', 'tag2', 'tag3']
const notes = 'random note'
const payloads = _.map(ids, id => _.map(tags, tag => {
        return ({
        accountId: id,
        tagId: tag,
        notes: notes
      })})).flat();
console.log(payloads);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Maddy Blacklisted
  • 1,190
  • 1
  • 7
  • 17
  • Thanks for the clarification. I tried doing that, but the `accountId` key is an array of ALL the ids for some reason – Noob May 03 '21 at 21:35
  • @Jav then there must be something else. I've added a runnable form of code snippet. Please try that out. It clearly shows the output that you want. – Maddy Blacklisted May 05 '21 at 11:46
  • It was an error with my input, thanks a lot for the explanation! – Noob May 05 '21 at 19:40
0

Try using map both times rather than forEach:

const ids = [1, 2, 3]
const tags = ['tag1', 'tag2', 'tag3']
const note = 'random note'

const results = _.flatten(_.map(ids, id => _.map(tags, tag => ({
  accountId: id,
  tagId: tag,
  notes: note
}))));

console.log(results)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>

Plain JavaScript:

const ids = [1, 2, 3]
const tags = ['tag1', 'tag2', 'tag3']
const note = 'random note'

const results = ids.map(id => tags.map(tag => ({
    accountId: id,
    tagId: tag,
    notes: note
}))).flat();

console.log(results)
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57