Advice on JSON format

Please can people tell me which of these JSON formats is the most appropriate?

  1. Object.
{
  "services":
  {
    "nodered":{"State":"running","enabled":"enabled"},
    "mariadb":{"State":"running","enabled":"enabled"}
  }
}
  1. Array.
{
  "services":
  [
    {"name":"nodered","State":"running","enabled":"enabled"},
    {"name":"mariadb","State":"running","enabled":"enabled"}
  ]
}

Using the first I can easily get msg.payload.services.nodered.State or msg.payload.services.mariadb.State

This is not so easy with the second, array format, but I think it will be easier to make a dashboard table to show the status.

My aim is a dashboard showing the status of multiple services as LEDs, grey for not installed, green for running, red for stopped.

Is there a right answer? :sweat_smile:

My vote will be for an array - but that's just because I prefer to use arrays for table things
(sorry I know that isn't helpful)

Will you need to specifically call msg.payload.services.nodered.State with in the dashboard?
can you not do everything within a loop? $(this).State

Disclaimer; I don't use dashboards

I'm hoping so :grinning:

I am not sure that I'll need msg.payload.services.nodered.State, it's just easy to feed into a debug node.

I hope I won't use $(this).State either, I'm allergic to any syntax including "this" or "scope"!

1 Like

My golden rule is to do whatever is simpler for me to implement, unless there is a powerful reason not to, which there usually is not.

Colin

1 Like

Leaving aside the Dashboard question for a moment, I'd also suggest a tweak to this object version.

{
  "services":
  {
    "nodered":{"name":"nodered", "State":"running","enabled":"enabled"},
    "mariadb":{"name":"mariadb", "State":"running","enabled":"enabled"}
  }
}

The reason being that you can now easily process both as an object and an array depending on need.

Objects are best for reference by name. msg.services.nodered for example. But if you then needed to walk through all of the services, you might want to do something like:

Object.values(msg.services).forEach( service => {
    ...
})

Where having the name still inside the inner data - while slightly larger in size, still gives you access to the name without having to faff with looping through the keys and having to access the inner object by keyname.

I quite often use that format when I think I might want to process the data both as an object and an array.

If using the array format, if you want a single entry, you are forced to use a filter to process the array. the object format lets you access any entry directly. So I rarely use the array format unless I'm certain in advance that I will never need to reference a single entry.

That's nicely thought out and explained. A useful technique, thanks :grinning:

My data passed from Pi to Node-red is more than just installed services. It's structure is not yet set , currently it looks like this.

{
  "services":
  [
    {"Id":"mariadb.service","ActiveState":"active","SubState":"running","UnitFileState":"enabled"}, 
     {"Id":"nodered.service","ActiveState":"active","SubState":"running","UnitFileState":"enabled"}, 
     {"Id":"mosquitto.service","ActiveState":"active","SubState":"running","UnitFileState":"enabled"},
     {"Id":"influxdb.service","ActiveState":"inactive","SubState":"dead","UnitFileState":""},
     {"Id":"log2ram.service","ActiveState":"inactive","SubState":"dead","UnitFileState":""}
  ],
  "memory":{"units":"MB","total":3793,"used":226,"free":3124,"available":3492},
  "disk":
  [
    {"filesystem":"/dev/root","mount":"/","size":112390,"used":3594,"available":104196,"percentused":4,"units":"MB"},
    {"filesystem":"/dev/sda1","mount":"/boot","size":255,"used":31,"available":225,"percentused":12,"units":"MB"}
  ],
  "ip":"192.168.1.12",
  "pihole":"enabled",
  "overlayFS":"Not installed"
}

The whole thing is so ugly that my inner protest "but name mariadb inside a mariadb object is redundant" is very easy to ignore!

You have awoken the tidy freak In me now!

You could partition it further?

Might not be for some, but dealing with .NET namespaces in my professional setting, I couldn't miss the opportunity :sweat_smile:

{
  "services": [
     {"Id":"mariadb.service","ActiveState":"active","SubState":"running","UnitFileState":"enabled"}, 
     {"Id":"nodered.service","ActiveState":"active","SubState":"running","UnitFileState":"enabled"}, 
     {"Id":"mosquitto.service","ActiveState":"active","SubState":"running","UnitFileState":"enabled"},
     {"Id":"influxdb.service","ActiveState":"inactive","SubState":"dead","UnitFileState":""},
     {"Id":"log2ram.service","ActiveState":"inactive","SubState":"dead","UnitFileState":""}
  ],
  "utilisation":{
     "memory":{"units":"MB","total":3793,"used":226,"free":3124,"available":3492},
     "storage":{
        "overlayFS": "not enabled",
        "volumes": [
          {"filesystem":"/dev/root","mount":"/","size":112390,"used":3594,"available":104196,"percentused":4,"units":"MB"},
          {"filesystem":"/dev/sda1","mount":"/boot","size":255,"used":31,"available":225,"percentused":12,"units":"MB"}
        ]
    }
   },
   "network":{
      "ip":"192.168.1.12",
      "pihole":"enabled"
    }
}

Thing is, the different sections are ripped from the output of different commands - services from
systemctl show nodered --property=Id,ActiveState,SubState,UnitFileState,
memory from free -m etc.

At the moment thay are just concatenated.

One day they'll all get displayed in an tidy and elegant dashboard.

If only I could discipline myself not to juggle SD cards and Pies I could just remember which one has what.

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