Search code examples
jsonjolt

Grab objects level below w JOLT


From REST API I receive next JSON:

[
  {
    "id": 1,
    "content": {
      "icon_256x256": {
        "flags": [],
        "id": 26864619,
        "type": "static"
      },
      "image_1080x607": {
        "flags": [],
        "id": 26864707,
        "type": "static"
      }
    },
    "status": "blocked",
    "textblocks": {
      "cta_sites_full": {
        "text": "learnMore",
        "title": ""
      },
      "text_220": {
        "text": "Domain",
        "title": ""
      },
      "text_90": {
        "text": "Don't worry, be happy!",
        "title": "Test!"
      }
    },
    "urls": {
      "primary": {
        "id": 90970124,
        "preview_link": "",
        "url_types": [
          "external_new",
          "external"
        ]
      },
      "url_slide_1": {
        "id": 90970124,
        "preview_link": "",
        "url_object_type": "domain"
      }
    },
    "user_can_request_remoderation": false
  },
  {
    "id": 2,
    "content": {
      "icon_256x256": {
        "flags": [],
        "id": 268,
        "type": "static"
      },
      "image_1080x607": {
        "flags": [],
        "id": 2686,
        "type": "static"
      }
    },
    "status": "blocked",
    "textblocks": {
      "cta_sites_full": {
        "text": "learnMore",
        "title": ""
      },
      "text_220": {
        "text": "Domain",
        "title": ""
      },
      "text_90": {
        "text": "ANOTHER TEXT",
        "title": "Test!"
      }
    },
    "urls": {
      "primary": {
        "id": 90970124,
        "preview_link": "",
        "url_types": [
          "external_new",
          "external"
        ]
      },
      "url_slide_1": {
        "id": 90970124,
        "preview_link": "",
        "url_object_type": "domain"
      }
    },
    "user_can_request_remoderation": false
  }
]

I want to grab from content objects 1 level below: in this case it's icon_256x256 and image_1080x607 and grab field id and stay it like it was, but only need id field. Also I need field textblocks and inside urls do the same like with content. So I expect to get this result:

[
   {
      "content":{
         "icon_256x256":{
            "id":26864619
         },
         "image_1080x607":{
            "id":26864707
         }
      },
      "status":"blocked",
      "textblocks":{
         "cta_sites_full":{
            "text":"learnMore",
            "title":""
         },
         "text_220":{
            "text":"Domain",
            "title":""
         },
         "text_90":{
            "text":"Don't worry, be happy!",
            "title":"Test!"
         }
      },
      "urls":{
         "primary":{
            "id":90970124
         },
         "url_slide_1":{
            "id":90970124
         }
      }
   },
   {
      "content":{
         "icon_256x256":{
            "id":268
         },
         "image_1080x607":{
            "id":2686
         }
      },
      "status":"blocked",
      "textblocks":{
         "cta_sites_full":{
            "text":"learnMore",
            "title":""
         },
         "text_220":{
            "text":"Domain",
            "title":""
         },
         "text_90":{
            "text":"Don't worry, be happy!",
            "title":"Test!"
         }
      },
      "urls":{
         "primary":{
            "id":90970124
         },
         "url_slide_1":{
            "id":90970124
         }
      }
   }
]

Objects inside content may have different names, like video_landscape instead of icon_256x256, so I can't loop based on names. But it always 1 level below, as you can see. Same for urls field. I hope I describe it clear!

My attempt was, but it doesn't work(:

[
  {
    "operation": "shift",
    "spec": {
      "content": {
        "*": {
          "id": "content.&1.id"
        }
      },
      "textblocks": {
        "@": "textblocks.&"
      },
      "urls": {
        "primary": {
          "id": "urls.primary.id"
        }
      }
    }
  }
]

Solution

  • You can use the following shift transformation spec :

    [
      {
        "operation": "shift",
        "spec": {
          "*": {
            "content|urls": {
              "*": {
                "id": "&2.&1.id" // &2 represents going 2 levels up in order to grab
                                 // the keys content and urls
                                 // and &1 stands for getting the respective subkeys 
                                 // of them from just one level up
              }
            },
            "status|textblocks": "&" // replicate the values of these attributes respectively
          }
        }
      }
    ]
    

    Edit ( based on your comment : "What if inside JSON there will be multiple objects? With same structure (id, content, etc)." ) :

    Then use the following one, having not seen the new desired output, thinking that you have probably want to have an array of objects rather than some leaf node arrays which are generated in this case :

    [
      {
        "operation": "shift",
        "spec": {
          "*": {
            "content|urls": {
              "*": {
                "id": "[&3].&2.&1.&"
              }
            },
            "status|textblocks": "[&1].&"
          }
        }
      }
    ]