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.

This has been added as an issue.

Was that you @Ben?

I suggested a simple implementation.

There is a pending PR: Added jsondelete operator to fix #9371 by SmartDever02 · Pull Request #9390 · TiddlyWiki/TiddlyWiki5 · GitHub

1 Like

I swear I checked first. Don’t know how I missed it. Ok, I’ll take a look.

Thanks!

Yes, that was me. Even if I decided to use several tiddlers and only data dictionary tiddlers, because thats way easier to handle in my case. Plus it is too easy for me to mess up the Jsontiddler with jsonset.

1 Like

If my understand correct, you can delete the line "b":

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

You can delete top-level indexes from a JSON tiddler by using:

<$action-setfield $tiddler="SomeTiddler" $index="b"/>

However, if you want to delete a nested JSON object (i.e., NOT a top-level index), then the above $action-setfield widget cannot be used… at least, not directly.

Instead, you need to use a combination of jsonextract and jsonset filter operators to fetch the existing JSON tiddler content and construct a new nested JSON definition that excludes the desired object. Only then can you overwrite the JSON tiddler’s entire text field to replace the existing JSON definition with the newly constructed JSON definition.

For example code, see my previous post here:

-e

I will just add that hierarchical JSON’s can be flattened, easily with a click using the JSON Manger Plugin. GitHub my wiki copy here

The result is one compound key that can be retrieved and read getting its value and presumably deleting by giving it a “” value. Theoretically you can search the resulting compound keys to find the one (or more) you want.

  • I have not tested this yet
  • Apparently you can set a value to nul and it will return nothing and not delete the item