问题
I have json that looks like the below. I'd like to get an output that contains one line for each timer record, but includes the name of the service.
{
"services":{
"service":[
{
"name":"Test Value",
"timer":[
{ "datetime":"08/30/2017 16:33:35", "value":"625" },
{ "datetime":"08/30/2017 16:22:38", "value":"240" }
]
},
{
"name":"Test Value 2",
"timer":[
{ "datetime":"08/30/2017 16:07:38", "value":"432" },
{ "datetime":"08/30/2017 15:59:07", "value":"1355" }
]
}
]
}
}
I've come up with .services.service[].name as $name | .services.service[].timer | map([ $name, .datetime, .value ])
, which gets me
[["Test Value","08/30/2017 16:33:35","625"],["Test Value","08/30/2017 16:22:38","240"]]
[["Test Value","08/30/2017 16:07:38","432"],["Test Value","08/30/2017 15:59:07","1355"]]
[["Test Value 2","08/30/2017 16:33:35","625"],["Test Value 2","08/30/2017 16:22:38","240"]]
[["Test Value 2","08/30/2017 16:07:38","432"],["Test Value 2","08/30/2017 15:59:07","1355"]]
The output that I'm expecting would be
[["Test Value","08/30/2017 16:33:35","625"],["Test Value","08/30/2017 16:22:38","240"]]
[["Test Value 2","08/30/2017 16:07:38","432"],["Test Value 2","08/30/2017 15:59:07","1355"]]
But notice that the values are duplicated for both services and sets of timers. What am I missing?
回答1:
.services.service[]|[{name,timer:.timer[]}|[.name,.timer[]]]
will give you your expected output,
.services.service[]|{name,timer:.timer[]}|[.name,.timer[]]
(without array aggregation) will give you one result for each timer:
["Test Value","08/30/2017 16:33:35","625"]
["Test Value","08/30/2017 16:22:38","240"]
["Test Value 2","08/30/2017 16:07:38","432"]
["Test Value 2","08/30/2017 15:59:07","1355"]
What you missed in your attempt is
The expression exp as $x | ... means: for each value of expression exp, run the rest of the pipeline with the entire original input, and with $x set to that value. Thus as functions as something of a foreach loop.
If you really want to use variables you need to do it like this: .services.service[]| .name as $name | .timer | map([ $name, .datetime, .value ])
回答2:
Here is another solution demonstrating array constructor variations. Note the placement of the [ ] in each is slightly different. With your data, this filter
.services.service[] | {name} + .timer[]
generates a single stream of objects
{"name":"Test Value","datetime":"08/30/2017 16:33:35","value":"625"}
{"name":"Test Value","datetime":"08/30/2017 16:22:38","value":"240"}
{"name":"Test Value 2","datetime":"08/30/2017 16:07:38","value":"432"}
{"name":"Test Value 2","datetime":"08/30/2017 15:59:07","value":"1355"}
this filter
.services.service[] | [ {name} + .timer[] ]
generates arrays of objects for each service
[{"name":"Test Value","datetime":"08/30/2017 16:33:35","value":"625"},{"name":"Test Value","datetime":"08/30/2017 16:22:38","value":"240"}]
[{"name":"Test Value 2","datetime":"08/30/2017 16:07:38","value":"432"},{"name":"Test Value 2","datetime":"08/30/2017 15:59:07","value":"1355"}]
this filter
.services.service[] | {name} + .timer[] | [.[]]
generates a stream of arrays
["Test Value","08/30/2017 16:33:35","625"]
["Test Value","08/30/2017 16:22:38","240"]
["Test Value 2","08/30/2017 16:07:38","432"]
["Test Value 2","08/30/2017 15:59:07","1355"]
and this filter
.services.service[] | [ {name} + .timer[] | [.[]] ]
generates arrays of arrays for each service
[["Test Value","08/30/2017 16:33:35","625"],["Test Value","08/30/2017 16:22:38","240"]]
[["Test Value 2","08/30/2017 16:07:38","432"],["Test Value 2","08/30/2017 15:59:07","1355"]]
回答3:
I think it would be helpful to try and visualize it in terms of the levels your data is in, and where you want it to be in your result. When flattening a hierarchy of data, I find it easier to think if it as taking values in one level, and combining it with the values from the next level.
So looking at the individual service objects, you want to take the name, and combine it with properties of its timer objects, and produce a results for each combination. So start there:
[.name] + (properties of the timer objects)
Then you need to generate the properties of the timer objects
.
.timer[] | [.datetime, .value]
You can read this as: "for each item in the timer
array, create an array consisting of the datetime
and value
properties."
Once you get everything at the same level, you could rearrange the values if you wanted, but fortunately in our case, everything is where we want them.
Put together, this expression produces individual arrays of the name, datetime, and values but you want to collect them in an array. So put them in.
[[.name] + (.timer[] | [.datetime, .value])]
When you put it all together, you'll get your result.
.services.service[] | [[.name] + (.timer[] | [.datetime, .value])]
来源:https://stackoverflow.com/questions/45982943/jq-get-each-value-in-array-with-parent