Mustache Template to create array of objects

Hello,

I have the need to take data from the array, msg.payload.devices and reformat it to msg.options as an array of objects. I am trying to use a Template node and mustache template to do so, but am having an issue. When outputting plain text from the template node, the template below appears to get everything I need, save it adds a trailing comma. Changing the output to Parsed JSON gives me an "Unexpected token } in JSON at position 206" error, which is the trailing comma.

How do I either get a mustache template to only include the comma between items, or, what would the syntax be to get me desired output? The ultimate goal is to populate the options in a dashboard's dropdown item.

Current Template adding trailing comma

[{
{{#payload.devices}}
   "{{name}}":"{{id}}",
{{/payload.devices}}
}]

Output from above template, as text

[{
   "Family Room Chromecast":"0ca5627c5089e7143a6856a8cd5e6abedb11dfce",
   "DESKTOP-NUVVO9O":"58460c1d747ba0c7a39afc8f6f56c0d7aff1cb72",
   "Squeezebox Touch":"ba7d99ac9fef8b737aa5cd75b86ebdae51689c38",
}]

Desired value of msg.options:
Note lack of trailing comma

[{
"Family Room Chromecast":"0ca5627c5089e7143a6856a8cd5e6abedb11dfce",
"DESKTOP-NUVVO9O":"58460c1d747ba0c7a39afc8f6f56c0d7aff1cb72",
"Squeezebox Touch":"ba7d99ac9fef8b737aa5cd75b86ebdae51689c38"
}]

Value of incoming msg.payload:

{
  "devices":[
     { 
          "id":"0ca5627c5089e7143a6856a8cd5e6abedb11dfce",
          "name":"Family Room Chromecast",
          "type":"TV",
          "volume_percent":100
     }, 
     {
          "id":"58460c1d747ba0c7a39afc8f6f56c0d7aff1cb72",
          "name":"DESKTOP-NUVVO9O",
          "type":"Computer",
          "volume_percent":100
     },
     {
          "id":"ba7d99ac9fef8b737aa5cd75b86ebdae51689c38",
          "name":"Squeezebox Touch",
          "type":"Speaker",
          "volume_percent":49
     }
  ]
} 

Nodes to create sample data

[
    {
        "id": "7ce770e8d2a76610",
        "type": "debug",
        "z": "bd80cf37.f9982",
        "name": "debug 48",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 560,
        "y": 1580,
        "wires": []
    },
    {
        "id": "e4f58aa89c01fb44",
        "type": "inject",
        "z": "bd80cf37.f9982",
        "name": "",
        "props": [
            {
                "p": "options",
                "v": "[{\"Family Room Chromecast\":\"0ca5627c5089e7143a6856a8cd5e6abedb11dfce\",\"DESKTOP-NUVVO9O\":\"58460c1d747ba0c7a39afc8f6f56c0d7aff1cb72\",\"Squeezebox Touch\":\"ba7d99ac9fef8b737aa5cd75b86ebdae51689c38\"}]",
                "vt": "json"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 230,
        "y": 1540,
        "wires": [
            [
                "53dab3083cf132e4",
                "7ce770e8d2a76610"
            ]
        ]
    },
    {
        "id": "0a455d4a96bc91ef",
        "type": "template",
        "z": "bd80cf37.f9982",
        "name": "",
        "field": "options",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": "[{\n{{#payload.devices}}\n   \"{{name}}\":\"{{id}}\",\n{{/payload.devices}}\n}]",
        "output": "json",
        "x": 360,
        "y": 1600,
        "wires": [
            [
                "53dab3083cf132e4",
                "7ce770e8d2a76610"
            ]
        ]
    },
    {
        "id": "bbaec4afeea8bf83",
        "type": "inject",
        "z": "bd80cf37.f9982",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "topic": "",
        "payload": "{\"devices\":[{\"id\":\"0ca5627c5089e7143a6856a8cd5e6abedb11dfce\",\"is_active\":false,\"is_private_session\":false,\"is_restricted\":false,\"name\":\"Family Room Chromecast\",\"type\":\"TV\",\"volume_percent\":100},{\"id\":\"58460c1d747ba0c7a39afc8f6f56c0d7aff1cb72\",\"is_active\":false,\"is_private_session\":false,\"is_restricted\":false,\"name\":\"DESKTOP-NUVVO9O\",\"type\":\"Computer\",\"volume_percent\":100},{\"id\":\"ba7d99ac9fef8b737aa5cd75b86ebdae51689c38\",\"is_active\":false,\"is_private_session\":false,\"is_restricted\":false,\"name\":\"Squeezebox Touch\",\"type\":\"Speaker\",\"volume_percent\":49}]}",
        "payloadType": "json",
        "x": 230,
        "y": 1600,
        "wires": [
            [
                "0a455d4a96bc91ef"
            ]
        ]
    }
]

I'm pretty sure you can do this with a change node and JSONata rather than struggling with Mustache.

I've not quite got it yet but close, this JSONata:

payload.devices.{
    name: id
}

Gives this:

[
    {
        "Family Room Chromecast": "0ca5627c5089e7143a6856a8cd5e6abedb11dfce"
    },
    {
        "DESKTOP-NUVVO9O": "58460c1d747ba0c7a39afc8f6f56c0d7aff1cb72"
    },
    {
        "Squeezebox Touch": "ba7d99ac9fef8b737aa5cd75b86ebdae51689c38"
    }
]

Got it:

[payload.devices{
    name: id
}]
[
  {
    "Family Room Chromecast": "0ca5627c5089e7143a6856a8cd5e6abedb11dfce",
    "DESKTOP-NUVVO9O": "58460c1d747ba0c7a39afc8f6f56c0d7aff1cb72",
    "Squeezebox Touch": "ba7d99ac9fef8b737aa5cd75b86ebdae51689c38"
  }
]
payload.devices.{
    name: id
}

device.{ says map devices and create an object for each array element.
device{ says group by each name property, use it as key and add id value , which does work for this data set, but might cause issue trying this with other data sets.

what you need to do is add a dollar
eg

payload.devices.${
    name: id
}

Which says map each device element and add them to the same object. Which may be better.

Its a mystery! :mage::magic_wand:

2 Likes

Just for info this Mustacge works, to some degree, not quite there though.

[{
{{#payload.devices}}
   "{{name}}":"{{id}}",
{{/payload.devices}}
"":""}]

This works

[{
{{#payload.devices.0}}
  "{{name}}":"{{id}}"
{{#payload.devices}}
   ,"{{name}}":"{{id}}"
{{/payload.devices}}
{{/payload.devices.0}}
}]

Thank you all for the replies. While the JSONata approach is very helpful, not a way I was aware of, and likely what I will go with, I am accepting the response which provides a working mustache template since that was the original request. I have need for the template method in other scenarios.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.