query when object name is a URL - json

I've written a JQ search that outputs the following, but I cannot work out how to get into the detail and extract specific information from this.
{
"https://www.example.org/rest/relation/node/recording/revision_uid": [
{
"_links": {
"self": {
"href": "https://www.example.org/user/37?_format=hal_json"
},
"type": {
"href": "https://www.example.org/rest/type/user/user"
}
},
"uuid": [
{
"value": "d40684cf-2321-42d2-9194"
}
]
}
],
"https://www.example.org/rest/relation/node/recording/uid": [
{
"_links": {
"self": {
"href": "https://www.example.org/user/37?_format=hal_json"
},
"type": {
"href": "https://www.example.org/rest/type/user/user"
}
},
"uuid": [
{
"value": "d40684cf-2321-42d2-9194"
}
],
"lang": "en"
}
],
"https://www.example.org/rest/relation/node/recording/field_category": [
{
"_links": {
"self": {
"href": "https://www.example.org/simplecategory?_format=hal_json"
},
"type": {
"href": "https://www.example.org/rest/type/taxonomy_term/tags"
}
},
"uuid": [
{
"value": "3fef93d5-926a-41aa-95cb"
}
]
}
],
"https://www.example.org/rest/relation/node/recording/field_part1_speaker": [
{
"_links": {
"self": {
"href": "https://www.example.org/by/speakername?_format=hal_json"
},
"type": {
"href": "https://www.example.org/rest/type/taxonomy_term/author"
}
},
"uuid": [
{
"value": "fb6c806f-fa6a-4aa0-89ef"
}
]
}
]
}
How do I write a query that returns 'https://www.example.org/simplecategory?_format=hal_json'?
And I'd then want a similar query that returns 'https://www.example.org/by/speakername?_format=hal_json'
So jq '._embedded' gets me the data above.
I've then tried various combinations to get to the value of https://www.example.org/rest/relation/node/recording/field_category.
- jq '._embedded.https://www.example.org/rest/relation/node/recording/field_category - but of course the URL has special characters in it.
jq .["https://www.example.org/rest/relation/node/recording/field_category"]
jq ."https://www.example.org/rest/relation/node/recording/field_category$"
I've also messed around with some of JQs built in functions, like flatten and to_entries, from_entries. I've also tried regular expressions but my efforts return Cannot iterate over null (null).

How do I write a query that returns 'https://www.example.org/simplecategory?_format=hal_json'?
If you want to specify the top-level key explicitly, the follow-on query would be:
.["https://www.example.org/rest/relation/node/recording/revision_uid"][]
| ._links.self.href
That is, the entire query would be:
._embedded
| .["https://www.example.org/rest/relation/node/recording/revision_uid"][]
| ._links.self.href
And I'd then want a similar query
An alternative to specifying the top-level key explicitly might be to select the href of interest from the array of all of them:
._embedded
| [.[][]._links.self.href]
This would yield:
[
"https://www.example.org/user/37?_format=hal_json",
"https://www.example.org/user/37?_format=hal_json",
"https://www.example.org/simplecategory?_format=hal_json",
"https://www.example.org/by/speakername?_format=hal_json"
]

Related

Merge Json Array Nodes and roll up a child element

I have a requirement to roll a collection of nodes that uses the current node name (within the collection) and for the value take each child nodes value (single node) into a string array, then use the parents key as the key.
Given.
{
"client": {
"addresses": [
{
"id": "27ef465ef60d2705",
"type": "RegisteredOfficeAddress"
},
{
"id": "b7affb035be3f984",
"type": "PlaceOfBusiness"
},
{
"id": "a8a3bef166141206",
"type": "EmailAddress"
}
],
"links": [
{
"id": "29a9de859e70799e",
"type": "Director",
"name": "Bob the Builder"
},
{
"id": "22493ad4c4fd8ac5",
"type": "Secretary",
"name": "Jennifer"
}
],
"Names": [
{
"id": "53977967eadfffcd",
"type": "EntityName",
"name": "Banjo"
}
]
}
}
from this the output needs to be
{
"client": {
"addresses": [
"RegisteredOfficeAddress",
"PlaceOfBusiness",
"EmailAddress"
],
"links": [
"Director",
"Secretary"
],
"Names": [
"EntityName"
]
}
}
What is the best way to achieve this? Any pointers to what/how to do this would be greatly appreciated.
Ron.
You can iterate over entries of your client object first with the help of the $each function, then get types for each of them, and combine via $merge:
{
"client": client
~> $each(function($list, $key) {{ $key: $list.type }})
~> $merge
}
Live playground: https://stedi.link/OpuRdE9

Fetching the array name when traversing array items in JSONata

I need to fetch the name of the array while traversing the child array items.
for example, if my input looks like
{"title": [
{
"value": "18724-100",
"locale": "en-GB"
},
{
"value": "18724-5",
"locale": "en-GB"
},
{
"value": "18724-99",
"locale": "fr-FR"
}
]}
I need output as
{
"data": [
{
"locale": "en-GB",
"metadata": [
{
"key": "title",
"value": "18724-100"
},
{
"key": "title",
"value": "18724-5"
}
]
},
{
"locale": "fr-FR",
"metadata": {
"key": "title",
"value": "18724-99"
}
}
]
}
I tried following spec in JSONata
{
"data": title{locale: value[]} ~> $each(function($v, $k) {
{
"locale": $k,
"metadata": $v.{"key": ???,"value": $}
}
})
}
Please help me to fill "???" so that I can get the array name
Assuming that the input object will always have a single root-level key you can write your expression like this:
{
"data": title{locale: value[]} ~> $each(function($v, $k) {
{
"locale": $k,
"metadata": $v.{"key": $keys($$)[0],"value": $}
}
})
}
$keys returns an array containing keys in the object. $keys($$) will return all keys in root-level of this array (in this case: "title").
Note that for a following input object:
{"title": [
{
"value": "18724-100",
"locale": "en-GB"
},
{
"value": "18724-5",
"locale": "en-GB"
},
{
"value": "18724-99",
"locale": "fr-FR"
}
],
"foo": 123
}
$keys($$) would return an array of two elements (["title", "foo"]).

Delete json block with jq command

I have json file with multiple domains which is formated as is showed below. How can I delete whole blocks with domains? For example if I will want to delete whole block in json for domain domain.tld?
I tryed this, but output is error:
jq '."http-01"."domain"[]."main"="domain.tld"' acme.json
jq: error (at acme.json:11483): Cannot iterate over null (null)
formating example file:
{
"http-01": {
"Account": {
"Email": "mail#placeholder.tld",
"Registration": {
"body": {
"status": "valid",
"contact": [
"mailto:mail#placeholder.tld"
]
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/110801506"
},
"PrivateKey": "main_priv_key_string",
"KeyType": "4096"
},
"Certificates": [
{
"domain": {
"main": "www.some_domain.tld"
},
"certificate": "cert_string",
"key": "key_string",
"Store": "default"
},
{
"domain": {
"main": "some_domain.tld"
},
"certificate": "cert_string",
"key": "key_string",
"Store": "default"
},
{
"domain": {
"main": "www.some_domain2.tld"
},
"certificate": "cert_string",
"key": "key_string",
"Store": "default"
},
{
"domain": {
"main": "some_domain2.tld"
},
"certificate": "cert_string",
"key": "key_string",
"Store": "default"
}
]
}
}
To delete domain block "www.some_domain.tld" :
jq '."http-01".Certificates |= map(select(.domain.main != "www.some_domain.tld"))' input.json
Your question is quite broad. What is a "block"?
Let's assume you want to delete from within the object under http-01 each field that is of type array and has at index 0 an object satisfying .domain.main == "domain.tld". Then first navigate to where you want to delete from, and update it (|=) using del and select which performs the filtered deletion.
jq '
."http-01" |= del(
.[] | select(arrays[0] | objects.domain.main == "domain.tld")
)
' acme.json
{
"http-01": {
"Account": {
"Email": "email#domain.tld",
"Registration": {
"body": {
"status": "valid",
"contact": [
"mailto:email#domain.tld"
]
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/110801506"
},
"PrivateKey": "long_key_string",
"KeyType": "4096"
}
}
}
Demo
If your "block" is deeper, go deeper before updating. If it is higher, the whole document for instance, there's no need to update, just start with del.

Read Array Value Using Dataweave in Mule

I am trying to use dataweave in Mule to read specific data values from an incoming payload. My sample payload looks like below:
{
"source": [
{
"uri": "entities/1R6xV",
"createdBy": "API_USER",
"createdTime": 1562504739146,
"attributes": {
"label": "000000000002659654",
"value": {
"Name": [
{
}
],
"Id": [
{
}
],
"Number": [
{
"type": "config/Types/Number/attributes/Number",
"ov": true,
"value": "000000000002659654",
"uri": "entities/1R6xV/attributes/Num/1ZtyT/Number/60pvN6"
}
]
}
}
}
]
}
If I need to read the "label", I can achieve that by
label: payload.source.attributes.label
Similarly, how can I read the "value" under attributes > Number. It doesn't work by:
Value: payload.source.attributes.Number.value
I am new to Dataweave. Please advise.
The problem is that the dot selector (.) works on object and on array of objects. When it is applied to an array it will apply the dot selector to all the elements of the array that are of type object and return that result.
Lets go part by part
payload.source
Returns
[
{
"uri": "entities/1R6xV",
"createdBy": "API_USER",
"createdTime": 1562504739146,
"attributes": {
"label": "000000000002659654",
"value": {
"Name": [
{
}
],
"Id": [
{
}
],
"Number": [
{
"type": "config/Types/Number/attributes/Number",
"ov": true,
"value": "000000000002659654",
"uri": "entities/1R6xV/attributes/Num/1ZtyT/Number/60pvN6"
}
]
}
}
}
]
So far so good as payload is an Object it returns the value of source that is an array
payload.source.attributes
Returns
[
{
"label": "000000000002659654",
"value": {
"Name": [
{
}
],
"Id": [
{
}
],
"Number": [
{
"type": "config/Types/Number/attributes/Number",
"ov": true,
"value": "000000000002659654",
"uri": "entities/1R6xV/attributes/Num/1ZtyT/Number/60pvN6"
}
]
}
}
]
Works ok because the result of payload.source was ended an Array of object so it will do that selection over those objects.
Now when you execute
payload.source.attributes.value.Number
It returns
[
[
{
"type": "config/Types/Number/attributes/Number",
"ov": true,
"value": "000000000002659654",
"uri": "entities/1R6xV/attributes/Num/1ZtyT/Number/60pvN6"
}
]
]
That is an array of arrays and here is where it is broken.
My Solution
You have two alternatives here
Use flatten function
flatten(payload.source.attributes.value.Number).value
Use descendant selector
payload.source.attributes.value.Number..value
Since Number is an array, you need to specify the index you want. In this case, the zeroth element:
Value: payload.source[0].attributes.value.Number[0].value
If you have multiple numbers, it would look something like this:
%dw 1.0
%output application/json
---
values: payload.source[0].attributes.value.Number map {
value: $.value
}

Filter only part of input using select

Given input like this:
{
"type": "collection",
"foo": "bar",
"children": [
{
"properties": {
"country": "GB"
},
"data": "..."
},
{
"properties": {
"country": "PL"
},
"data": "..."
}
]
}
How can I use jq to retain all of the JSON structure, but filter out some of the children using select(). For instance, If I wanted to return only children with country GB, I would expect the following output:
{
"type": "collection",
"foo": "bar",
"children": [
{
"properties": {
"country": "GB"
},
"data": "..."
}
]
}
If I only want the children, this is easy with .children[] | select(.properties.country == "GB"), but does not retain the rest of the JSON.
The key is to use |=. In the present case, you could use the following pattern:
.children |= map(select(...))