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"