Remove duplicate objects in JSON array with jq based on specific criteria - json

I have the following data where I want entire objects removed based on duplicate values of the "run" key, while keeping the object with the largest "startTime" number:
{
"data": {
"results": [
{
"event": {
"biking": {
"startTime": 12,
"id": "a",
"run": "x"
}
},
"displayName": "Alex"
},
{
"event": {
"biking": {
"startTime": 10,
"id": "b",
"run": "x"
}
},
"displayName": "Adam"
},
{
"event": {
"biking": {
"startTime": 11,
"id": "c",
"run": "y"
}
},
"displayName": "Aaron"
}
]
}
}
I've been trying to finagle unique with jq but can't quite get what I want. My intended result is this:
{
"data": {
"results": [
{
"event": {
"biking": {
"startTime": 12,
"id": "a",
"run": "x"
}
},
"displayName": "Alex"
},
{
"event": {
"biking": {
"startTime": 11,
"id": "c",
"run": "y"
}
},
"displayName": "Aaron"
}
]
}
}
I was trying to use unique because I want to keep only 1 of each "run": ids where in a larger list I might have three x, two y, and four z. I'd want to keep one x, y, and z in this case based on the largest "startTime".

Here's a straightforward jq solution:
.data.results |=
(group_by(.event.biking.run)
| map(max_by(.event.biking.startTime)))
It uses group_by to group by "run", and then max_by to select the desired event.

Here's how it can be done using reducer.
const input = {
"data": {
"results": [{
"event": {
"biking": {
"startTime": 12,
"id": "a",
"run": "x"
}
},
"displayName": "Alex"
},
{
"event": {
"biking": {
"startTime": 10,
"id": "b",
"run": "x"
}
},
"displayName": "Adam"
},
{
"event": {
"biking": {
"startTime": 11,
"id": "c",
"run": "y"
}
},
"displayName": "Aaron"
}
]
}
};
const output = {
data: {}
};
output.data.results = Object.values(input.data.results.reduce((r, o) => {
r[o.event.biking.run] =
(r[o.event.biking.run] &&
r[o.event.biking.run].event.biking.startTime > o.event.biking.startTime) ? r[o.event.biking.run] : o
return r
}, {}));
console.log(output);
Credits -> https://stackoverflow.com/a/56901839/8057127

This would work
const result = [
...new Map(
obj.data.results.map((item) => [item["event"]["biking"]["run"], item])
).values()
];
DEMO
This is based on helprjs removeDuplicates.

Related

Sort complex JSON object by specific property

How can I sort the given JSON object with property count. I want to sort the entire sub-object. The higher the count value should come on the top an so on.
{
"Resource": [
{
"details": [
{
"value": "3.70"
},
{
"value": "3.09"
}
],
"work": {
"count": 1
}
},
{
"details": [
{
"value": "4"
},
{
"value": "5"
}
],
"work": {
"count": 2
},
{
"details": [
{
"value": "5"
},
{
"value": "5"
}
],
"work": "null"
}
]
}
You can try this example to sort your data:
data = {
"data": {
"Resource": [
{
"details": [{"value": "3.70"}, {"value": "3.09"}],
"work": {"count": 1},
},
{"details": [{"value": "4"}, {"value": "5"}], "work": {"count": 2}},
]
}
}
# sort by 'work'/'count'
data["data"]["Resource"] = sorted(
data["data"]["Resource"], key=lambda r: r["work"]["count"]
)
# sort by 'details'/'value'
for r in data["data"]["Resource"]:
r["details"] = sorted(r["details"], key=lambda k: float(k["value"]))
# pretty print:
import json
print(json.dumps(data, indent=4))
Prints:
{
"data": {
"Resource": [
{
"details": [
{
"value": "3.09"
},
{
"value": "3.70"
}
],
"work": {
"count": 1
}
},
{
"details": [
{
"value": "4"
},
{
"value": "5"
}
],
"work": {
"count": 2
}
}
]
}
}

Extract parent node by filtering on child nodes

I need to filter JSON on some child elements and to extract the parent node id.
Part of the JSON:
[
{
"data": {
"id": "2da44298-05ec-4bb5-acce-b524ef56328c",
"attributes": {
"units": [
{
"id": "1492de82-2f36-43bf-b077-5cf54a3f38b9",
"show_name": false,
"children": [
{
"id": "a5d76efa-5b21-4874-a8a5-c9c9f8317ee6",
"contents": [
{
"id": "b96c127c-6a4f-4a29-924d-63f0ba55972a",
"link": {
"url": "#",
"target": "_blank",
"data": {
"aspect-ratio": null
}
},
"duration": null
},
{
"id": "dbb7e8fd-aa35-4acc-8ad7-1c7dcd08a6d8",
"link": {
"data": {
"id": "dbb7e8fd-aa35-4acc-8ad7-1c7dcd08a6d8",
"aspect-ratio": null
}
},
"duration": null
}
]
},
{
"id": "8a805cd0-7447-4fac-b4fc-aaa9a2f7e649",
"contents": [
{
"id": "d64138b6-5195-48b4-a0f7-b087c5496587",
"link": {
"data": {
"id": "d64138b6-5195-48b4-a0f7-b087c5496587",
"aspect-ratio": null
}
},
"duration": null
},
{
"id": "392406b1-fa20-413b-a98a-4d1a5b201d8e",
"link": {
"url": "#",
"target": "_blank",
"data": {
"id": "423498d9-8e0f-41ef-891a-34b078862ce7",
"aspect-ratio": null
}
},
"duration": null
}
]
}
],
"contents": []
}
],
"text": []
}
},
"jsonapi": {
"version": "1.0"
}
}
]
For example, it is required to extract unit id filtered on contents id b96c127c-6a4f-4a29-924d-63f0ba55972
I tried the following expressions:
$..data..?(#contents.data.id == 'b96c127c-6a4f-4a29-924d-63f0ba55972a')].id
$..data..?(#contents.data.id == 'b96c127c-6a4f-4a29-924d-63f0ba55972a')].children.id
$..data..?(#contents.data.id == 'b96c127c-6a4f-4a29-924d-63f0ba55972a')].unit.id
I need to do this way because of those ids are being got from different responses.
You could use nested filter operators to get the parent node, something like:
$..data.attributes.units.[?(#.children[?(#.content[?(#.id == 'b96c127c-6a4f-4a29-924d-63f0ba55972')])])].id
Demo:
More information: JMeter's JSON Path Extractor Plugin - Advanced Usage Scenarios

Aggregate and sum json data in python

I am new to python, using python3. I have json data like:
{
"message": {
"count": 46,
"limit": 1000,
"schools": [
{
"class": "1",
"class_id": "1c8***",
"charges": [
{
"cost": 10,
"breakdown": [
{
"books": "1",
"unitQuantity": "10"
}
]
}
],
"area": "maccau"
},
{
"class": "2",
"class_id": "1c3***",
"charges": [
{
"cost": 100,
"breakdown": [
{
"books": "1",
"unitQuantity": "100"
}
]
}
],
"area": "maccau"
},
{
"class": "1",
"class_id": "1c3***",
"charges": [
{
"cost": 10,
"breakdown": [
{
"books": "1",
"unitQuantity": "10"
}
]
}
],
"area": "maccau"
},
{
"class": "2",
"class_id": "1c8***",
"charges": [
{
"cost": 50,
"breakdown": [
{
"books": "1",
"unitQuantity": "50"
}
]
}
],
"area": "maccau"
}
],
"url": {
"link": "/"
}
}
}
I was able to use json.loads to load data and I am trying to get results like:
class Cost
1 20
2 150
I tried converting json to a dictionary:
item_dict = json.load(json_data)
Tried to get data out using for loop and checking if class = 1 and then summing up the cost. But I feel like that is not the best approach. Can someone please tell me what would be the best way of doing this?

Mapping the value of a json array using filter and groupby

My json is like below. I am trying to group my objects based on the role id for target id equal to 1083.
My json:
[ {
"id" :1,
"role": {
"id": "25",
},
"target": {
"id": "1083",
}
},
{
"id" :2,
"role": {
"id": "25",
},
"target": {
"id": "1083",
}
},
{
"id" :3,
"role": {
"id": "25",
},
"target": {
"id": "1084",
}
},
{
"id" :4,
"role": {
"id": "3",
},
"target": {
"id": "1083",
}
}
]
Expected result:
{
"25" : [
{
"id": 1
"role": {
"id": "25",
},
"target": {
"id": "1083",
}
},
{ "id": 2
"role": {
"id": "25",
},
"target": {
"id": "1083",
}
}
],
"3": [
{
"id" :4,
"role": {
"id": "3",
},
"target": {
"id": "1083",
}
}]
}
So for my result json, it's grouped by 25 and 3. The third record doesn't exist in my expected result as it's target id is 1084
I tried filter to get only target id 1083, but when I tried to use grouby, I am getting errors
data.filter(o => {
return o.target.id === "1083"
})
With lodash via filter and groupBy:
var data = [{ "id": 1, "role": { "id": "25", }, "target": { "id": "1083", } }, { "id": 2, "role": { "id": "25", }, "target": { "id": "1083", } }, { "id": 3, "role": { "id": "25", }, "target": { "id": "1084", } }, { "id": 4, "role": { "id": "3", }, "target": { "id": "1083", } } ]
const groupIt = (targetId) => _.chain(data)
.filter(x => x.target.id ===targetId)
.groupBy('role.id')
.value()
console.log(groupIt('1083'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You could achieve the same without lodash via filter and then reduce:
var data = [{ "id": 1, "role": { "id": "25", }, "target": { "id": "1083", } }, { "id": 2, "role": { "id": "25", }, "target": { "id": "1083", } }, { "id": 3, "role": { "id": "25", }, "target": { "id": "1084", } }, { "id": 4, "role": { "id": "3", }, "target": { "id": "1083", } } ]
const groupIt = (targetId) => data.filter(x => x.target.id === targetId)
.reduce((r, c) => (r[c.role.id] = [...r[c.role.id] || [], c], r), {})
console.log(groupIt('1083'))

Mongodb - Finding GeoNear within nested JSON objects

I need to get the closest place near a certain point using this data structure:
[
{
"data_id": "127",
"actual_data": [
{
"id": "220",
"value": "shaul"
},
{
"id": "221",
"value": "3234324"
},
{
"id": "222",
"value": {
"lngalt": [
13.7572225,
-124.0429047
],
"street_number": null,
"political": null,
"country": null,
}
},
{
"id": "223",
"value": "dqqqf1222fs3d7ddd77#Dcc11cS2112s.com"
},
{
"id": "224",
"value": "123123"
},
{
"id": "225",
"value": "lala1"
},
....
},
{
"data_id": "133",
"actual_data": [
{
"id": "260",
"value": {
"lngalt": [
1.7572225,
32.0429047
],
"street_number": null,
"political": null,
"country": null,
}
},
{
"id": "261",
"value": -122.25
}
],
}
]
I used the following query in order to get what I need:
{
"actual_data": {
"$elemMatch": {
"id": "260",
"value.lngalt": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [
-73.9667,
40.78
]
},
"$minDistance": 1000,
"$maxDistance": 5000
}
}
}
}
}
But after queering it, I get "Can't canonicalize query: BadValue geoNear must be top-level expr" (error code: 17287). It's strange since I do get the right results when I query without the $near but with $elemMatch only in order to get the exact object with particular value.
Thanks.
SOLVED!
for future refarance I used $geoWithin instead $near function. So my query looks like :
{
"actual_data": {
"$elemMatch": {
"id": "260",
"value.lnglat": {
"$geoWithin": {
"$centerSphere": [
[
-71.07651880000003,
42.353068
],
0.001
]
}
}
}
}
}
PEACE!