I am struggling to figure out an issue with manipulating JSON with Aeson lenses. My task is as simple as to add a key to a nested object in JSON. I was able to change the existing keyby means of:
> :set -XOverloadedStrings
> import Control.Lens
> import Data.Aeson
> import Data.Aeson.Lens
> "{ \"a\": { \"b\": 10 } }" & key "a" . key "b" .~ String "jee"
"{\"a\":{\"b\":\"jee\"}}"
But when I try to make it deal with the new key, it just silently fails to add it:
> "{ \"a\": { \"b\": 10 } }" & key "a" . key "c" .~ String "jee"
"{\"a\":{\"b\":10}}"
Certainly it's me doing something wrong, but I figure I'm out of mana to understand what exactly.
Would you kindly point me in the right direction?
Thank you!
As dfeuer noted, at
can insert into maps, while key
and ix
merely traverse elements if they exist. We can do the following:
> "{ \"a\": { \"b\": 10 } }" & key "a" . _Object . at "c" ?~ String "foo"
"{\"a\":{\"b\":10,\"c\":\"foo\"}}
at
is a lens focusing on Maybe element
-s, and we can insert by setting to Just
some element, and remove by setting to Nothing
. at "c" ?~ String "foo"
is the same as at "c" .~ Just (String "foo")
.
If we want to do nested inserts, we can use non
to define a default value to be inserted:
> "{ \"a\": { \"b\": 10 } }" & key "a" . _Object . at "c" . non (Object mempty) . _Object . at "d" ?~ String "foo"
"{\"a\":{\"b\":10,\"c\":{\"d\":\"foo\"}}}"
This is a mouthful, so we can factor some parts out:
> let atKey k = _Object . at k
> "{ \"a\": { \"b\": 10 } }" & key "a" . atKey "c" . non (Object mempty) . atKey "d" ?~ String "foo"
key
is based on ix
, whose documentation indicates it isn't powerful enough to do what you want and points to Control.Lens.At.at
. I'm pretty sure that should do the trick for you. The basic idea is that you start with the _Object
prism to turn the JSON text into an object, then use at key
to get a lens into that field as a Maybe
. You can then change it to Just
what you want.
This will work very well as long as all the objects along the path you wish to take exist. If you want to (potentially) start from nothing and create a chain of single-field objects, you will likely find things more annoying. Fortunately, you probably don't need to do this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With