When working with flat JSON structures like your example, it’s much easier to use the $action-setfield widget with the $index attribute and no $value. It’s somewhat unintuitive, but the key phrase is here in the docs (bolded for emphasis):
$value
The value to be assigned to the field or index identified by the $field or $index attribute. If neither is specified then the value is assigned to the text field. If no value is specified, $field or $index will be deleted.
So to delete index “b”, you could use
<$action-setfield $tiddler="MyJSON" $index="b" />
And conversely, to add a new index “d”, you could use
<$action-setfield $tiddler="MyJSON" $index="d" $value="four" />
In either case (as with any $action- widget), $action-setfield needs to be used with a trigger like $button. So your functional code might look something like this:
<$button>
delete index "b"
<$action-setfield $tiddler="MyJSON" $index="b" />
</$button>
or
\procedure delete-index-b()
<$action-setfield $tiddler="MyJSON" $index="b" />
\end
<$button actions=<<delete-index-b>> >
delete index "b"
</$button>
IMO, since $action-setfield sets the precedent of using a single action widget to set both fields and indexes, you might reasonably expect $action-deletefield to have a similar affordance. But $action-deletefield doesn’t support an $index attribute (at least as of v5.3.8), so we have to use this $action-setfield workaround for indexes.