Merging/Consolidating Child Items of the same parent element

Hi,
I am trying to consolidate items that have similar parent item. I tried with item list node but wasn’t able to figure out if its the right option. I need item_attribute_values which have similar attribute_name to be consolidated under one element. For example, one Duration attribute name with 1-Hour and 2-Hours and one Diving Gear which has two attribute value items “Included” and “Excluded”.

Appreciate if someone can guide me in the right direction, thanks.

[
	{
		"attribute_name": "Kayak Type",
		"item_attribute_values": [
			{
				"attribute_value": "single-kayak",
				"abbr": "pa_kayak-type"
			}
		]
	},
	{
		"attribute_name": "Duration",
		"item_attribute_values": [
			{
				"attribute_value": "1-hour",
				"abbr": "pa_duration"
			}
		]
	},
	{
		"attribute_name": "Duration",
		"item_attribute_values": [
			{
				"attribute_value": "2-hours",
				"abbr": "pa_duration"
			}
		]
	},
	{
		"attribute_name": "Diving Gear",
		"item_attribute_values": [
			{
				"attribute_value": "Excluded",
				"abbr": "diving-gear"
			}
		]
	},
	{
		"attribute_name": "Diving Gear",
		"item_attribute_values": [
			{
				"attribute_value": "Included",
				"abbr": "diving-gear"
			}
		]
	}
]

Assuming the output is an array on multiple items instead of an array of one item. You can use the following function node.

const attributeNames = {}

for (const item of items) {
  if (attributeNames.hasOwnProperty(item.json.attribute_name)) continue
  else {
    attributeNames[item.json.attribute_name] = [];
  }
}

for (const item of items) {
   attributeNames[item.json.attribute_name].push(...item.json.item_attribute_values) 
}

return [
  {
    json: {
      ...attributeNames,
    }
  }
]
Example workflow
{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "\nreturn [\n    {\n      json: {\n        \t\t\"attribute_name\": \"Kayak Type\",\n\t\t\"item_attribute_values\": [\n\t\t\t{\n\t\t\t\t\"attribute_value\": \"single-kayak\",\n\t\t\t\t\"abbr\": \"pa_kayak-type\"\n\t\t\t}\n\t\t]\n      }\n    },\n    {\n      json: {\n      \t\t\"attribute_name\": \"Duration\",\n\t\t\"item_attribute_values\": [\n\t\t\t{\n\t\t\t\t\"attribute_value\": \"1-hour\",\n\t\t\t\t\"abbr\": \"pa_duration\"\n\t\t\t}\n\t\t]\n      }\n    },\n    {\n      json: {\n        \t\n\t\t\"attribute_name\": \"Diving Gear\",\n\t\t\"item_attribute_values\": [\n\t\t\t{\n\t\t\t\t\"attribute_value\": \"Excluded\",\n\t\t\t\t\"abbr\": \"diving-gear\"\n\t\t\t}\n\t\t]\n      }\n    },\n        {\n      json: {\n        \t\t\"attribute_name\": \"Diving Gear\",\n\t\t\"item_attribute_values\": [\n\t\t\t{\n\t\t\t\t\"attribute_value\": \"Included\",\n\t\t\t\t\"abbr\": \"diving-gear\"\n\t\t\t}\n\t\t]\n      }\n    }\n\n]\n\n"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        540,
        300
      ],
      "notesInFlow": true,
      "notes": "Mockup data"
    },
    {
      "parameters": {
        "functionCode": "const attributeNames = {}\n\nfor (const item of items) {\n  if (attributeNames.hasOwnProperty(item.json.attribute_name)) continue\n  else {\n    attributeNames[item.json.attribute_name] = [];\n  }\n}\n\nfor (const item of items) {\n   attributeNames[item.json.attribute_name].push(...item.json.item_attribute_values) \n}\n\nreturn [\n  {\n    json: {\n      ...attributeNames,\n    }\n  }\n]"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        760,
        300
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

@RicardoE105 Thanks a lot for your continuous support… Its close to what I am trying to achieve, two things:

  • The function returns a single list/result, I need to send one HTTP request for each attribute name + attribute values (same structure as the json example I provided)
  • The rest api I am using expects to have attribute name, the function you shared strips the attribute name/key (same structure as the json example I provided)

Gotcha. In that case, the function below should do it:

const attributeNames = {}

for (const item of items) {
  if (attributeNames.hasOwnProperty(item.json.attribute_name)) continue
  else {
    attributeNames[item.json.attribute_name] = [];
  }
}

for (const item of items) {
   attributeNames[item.json.attribute_name].push(...item.json.item_attribute_values) 
}

return Object.keys(attributeNames).map(attributeName => ({ json: { attribute_name: attributeName, item_attribute_values: attributeNames[attributeName]   } }))
Example workflow
{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "\nreturn [\n    {\n      json: {\n        \t\t\"attribute_name\": \"Kayak Type\",\n\t\t\"item_attribute_values\": [\n\t\t\t{\n\t\t\t\t\"attribute_value\": \"single-kayak\",\n\t\t\t\t\"abbr\": \"pa_kayak-type\"\n\t\t\t}\n\t\t]\n      }\n    },\n    {\n      json: {\n      \t\t\"attribute_name\": \"Duration\",\n\t\t\"item_attribute_values\": [\n\t\t\t{\n\t\t\t\t\"attribute_value\": \"1-hour\",\n\t\t\t\t\"abbr\": \"pa_duration\"\n\t\t\t}\n\t\t]\n      }\n    },\n    {\n      json: {\n        \t\n\t\t\"attribute_name\": \"Diving Gear\",\n\t\t\"item_attribute_values\": [\n\t\t\t{\n\t\t\t\t\"attribute_value\": \"Excluded\",\n\t\t\t\t\"abbr\": \"diving-gear\"\n\t\t\t}\n\t\t]\n      }\n    },\n        {\n      json: {\n        \t\t\"attribute_name\": \"Diving Gear\",\n\t\t\"item_attribute_values\": [\n\t\t\t{\n\t\t\t\t\"attribute_value\": \"Included\",\n\t\t\t\t\"abbr\": \"diving-gear\"\n\t\t\t}\n\t\t]\n      }\n    }\n\n]\n\n"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        620,
        300
      ],
      "notesInFlow": true,
      "notes": "Mockup data"
    },
    {
      "parameters": {
        "functionCode": "const attributeNames = {}\n\nfor (const item of items) {\n  if (attributeNames.hasOwnProperty(item.json.attribute_name)) continue\n  else {\n    attributeNames[item.json.attribute_name] = [];\n  }\n}\n\nfor (const item of items) {\n   attributeNames[item.json.attribute_name].push(...item.json.item_attribute_values) \n}\n\nreturn Object.keys(attributeNames).map(attributeName => ({ json: { attribute_name: attributeName, item_attribute_values: attributeNames[attributeName]   } }))"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        840,
        300
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
1 Like

@RicardoE105 Thanks a lot, its exactly what I am looking for, thanksss.