Delete JSON Object

Hey there,
I’m still stuggling with JSON. I do understand now how to read and write data in JSON. Now I’m trying to delete for example “b” in the example below:

{
    "a": "one",
    "b": "two",
    "c": "three",
}

The only JSON-Operator that is changing the data is jsonset, as far as I know. But I don’t find a solution with it.

Thank’s for your help,
Ben

1 Like

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.

2 Likes

Thanks for your quick response. That helped a lot already. Unfortunatly I’m also looking for a way to delete “f” in this example:

{
    "a": "one",
    "b": "",
    "c": "three",
    "d": {
        "e": "four",
        "f": [
            "five",
            "six",
            true,
            false,
            null
        ],
        "g": {
            "x": "max",
            "y": "may",
            "z": "maize"
        }
    }
}

Your answer sounds like there is also a way to do this?

Deleting an object from nested JSON is a bit tricky, but can be done.

Here’s some example code:

\procedure jsondel(tid,del,from)
<$let json={{{ [<tid>get[text]] }}}>
<$let old={{{ [<json>jsonextract<from>] }}}>
<$let new={{{ [<old>jsonindexes[]] -[<del>]
   :map[<old>jsonextract<currentTiddler>addprefix[":]addprefix<currentTiddler>addprefix["]]
   +[join[,]addprefix[{]addsuffix[}]] }}}>
<$let json={{{ [<json>jsonset:json<from>,<new>] }}}>

<$button>
   DELETE <<del>> from <<from>> in <<tid>>
   <$action-setfield $tiddler=<<tid>> text=<<json>>/>
</$button>
\end

<<jsondel tid:"jsondata" del:"f" from:"d">>

Notes:

  • line 1: get the current JSON data from the tiddler
  • line 2: extract the “parent object” (d) from the JSON data
  • line 3: get the object indexes (e,f,g) and remove the index to be deleted (f)
  • line 4: for each remaining index (e,g), extract the current value and add the index name (in quotes) before it
  • line 5: join the indexes to form a new object enclosed in {...}
  • line 6: construct the new JSON data, replacing the existing “parent object” value with the new object
  • Then, use a $button widget to update the tiddler’s content with the new json

enjoy,
-e

Unfortunately, TW isn’t really (1) optimized (2) for working with nested JSON structures. Personally, I’d love to see a core modification to $action-setfield like the one @EricShulman suggested here (or even a new $action-setjson widget, as @jeremyruston suggested last time I brought this up). This would presumably let us use the missing-$value trick to delete an index, in addition to making it generally easier to set JSON index values. But in the meantime, I have to recommend you try to avoid complex JSON objects if at all possible. :confused:

I think you should raise an issue at GitHub. I think we should add a jsondelete operator.