Get unflatten field from json object with json path - json

I have a json object:
{
"context": [
{"name": "John", "node": [{"id": 1, "detail": "hello"}, {"id": 2, "detail": "world"}]},
{"name": "Andy", "node": [{"id": 3, "detail": "andy"}]},
{"name": "Dave", "node": [{"id": 4, "detail": "dave"}]},
]
}
and I want to get the list of detail of each person
[
["hello", "world"],
["andy"],
["dave"],
]
I am wondering if this is even possible? I have tried many things but the array got flatten out and that is not ideal.

The json you provide isn't valid (so I added a name of the array):
{
"persons": [
{"name": "John", "node": [{"id": 1, "detail": "hello"}, {"id": 2, "detail": "world"}]},
{"name": "Andy", "node": [{"id": 3, "detail": "andy"}]},
{"name": "Dave", "node": [{"id": 4, "detail": "dave"}]},
]
}
To get all details here:
$..detail
the result of it is:
[
"hello",
"world",
"andy",
"dave"
]
tested with http://jsonpath.curiousconcept.com/ (Jsonpath 0.8.3)

Okay, I'm guessing your JSON should be an array of objects and not an object containing an array. If so, then this is how you could do it;
$json = <<<EOF
[
{"name": "John", "node": [{"id": 1, "detail": "hello"},{"id": 2, "detail": "world"}]},
{"name": "Andy", "node": [{"id": 3, "detail": "andy"}]},
{"name": "Dave", "node": [{"id": 4, "detail": "dave"}]}
]
EOF;
$map = array_map(function($object) {
return array_map(function($detail) {
return $detail->detail;
}, $object->node);
}, json_decode($json));
This would then give you the values in the structure you want;
[
['hello', 'world'],
['andy'],
['dave']
]

The sample JSON has one excess comma. Assuming it has been removed, the following invocation:
jq -cf '[.context[] | [.node[] | .detail]]' input.json
produces:
[["hello","world"],["andy"],["dave"]]
http://stedolan.github.io/jq is very similar to JSONpath. See "jq for JSONpath users".

Related

is this even possible with `jq`?

I have some JSON data that looks like this
[
{Key: "fruits/red/apple", Value: "Red apples"},
{Key:"fruits/green/lime", Value: "Green Limes"},
{Key: "fruits/blue/berries/blueberry", Value: "Blue Berries"},
{Key: "vegetables/red/tomato", Value: "Red Tomatoes"},
{Key: "vegetables/green/cucumber", Value: "Green Cucumbers"}
]
And I am trying to extract the data to a nested JSON-tree structure like
{
"fruits": {
"id": 1,
"name": "fruits",
"children": [
{
"id": 2,
"name": "red",
"path": 1.2,
"children": [ { "id": 3, "name": "apple", "path": 1.2.3 } ]
},
{
"id: 4,
"name": "green",
"path": 1.4,
"children": [ {"id": 5, "name": "lime", "path": 1.4.5} ]
},
{
"id: 6,
"name": "blue",
"path": 1.6,
"children": [ {"id": 7, "name": "berries", "path": 1.6.7, "children": [{...}] } ]
}
]
},
"vegetables": {...}
}
I am new to jq and have something like this that gives me one level of data, but am lost on how to do running counters and recursion
[ .[] | { name: .Key, description: .Value, children: ( [.Key | split("/")] | .[0] | to_entries ) } ]
appreciate any pointers on this.
The desired output is not JSON, and it would be difficult to produce those non-numeric paths (e.g. 1.2.3). You could obviously add quotation marks to make them strings, but it would be much better to choose a more standard or convenient path representation.
Other than that, you can rest assured that jq is up to the task, though it would require some expertise in programming generally, or at least fluency with jq.

Using jq to convert object to key with values

I have been playing around with jq to format a json file but I am having some issues trying to solve a particular transformation. Given a test.json file in this format:
[
{
"name": "A", // This would be the first key
"number": 1,
"type": "apple",
"city": "NYC" // This would be the second key
},
{
"name": "A",
"number": "5",
"type": "apple",
"city": "LA"
},
{
"name": "A",
"number": 2,
"type": "apple",
"city": "NYC"
},
{
"name": "B",
"number": 3,
"type": "apple",
"city": "NYC"
}
]
I was wondering, how can I format it this way using jq?
[
{
"key": "A",
"values": [
{
"key": "NYC",
"values": [
{
"number": 1,
"type": "a"
},
{
"number": 2,
"type": "b"
}
]
},
{
"key": "LA",
"values": [
{
"number": 5,
"type": "b"
}
]
}
]
},
{
"key": "B",
"values": [
{
"key": "NYC",
"values": [
{
"number": 3,
"type": "apple"
}
]
}
]
}
]
I have followed this thread Using jq, convert array of name/value pairs to object with named keys and tried to group the json using this expression
jq '. | group_by(.name) | group_by(.city) ' ./test.json
but I have not been able to add the keys in the output.
You'll want to group the items at the different levels and building out your result objects as you want.
group_by(.name) | map({
key: .[0].name,
values: (group_by(.city) | map({
key: .[0].city,
values: map({number,type})
}))
})
Just keep in mind that group_by/1 yields groups in a sorted order. You'll probably want an implementation that preserves that order.
def group_by_unsorted(key_selector):
reduce .[] as $i ({};
.["\($i|key_selector)"] += [$i]
)|[.[]];

mongodb find() returns entire db, even with parameter

I have the following db:
{
"a": [{
"name": "foo",
"thing": [{
"name": "bar",
"lyrics": ["1", "2", "3"]
}]
}, {
"name": "abc",
"thing": [{
"name": "123",
"list": ["one", "two"]
}]
}]
}
I can't seem to query it correctly. These two queries return the same thing, the entire db:
db.test.find({"a.name":"abc"})
db.test.find({"a.name":"foo"})
How do I find one collection instead of the whole db?
I would expect the first query to return:
{
"name": "abc",
"thing": [{
"name": "123",
"list": ["one", "two"]
}]
}
The two queries return the same document, because both queries match it.
This is one document
[{
"a": [{
"name": "foo",
"thing": [{
"name": "bar",
"lyrics": ["1", "2", "3"]
}]
}, {
"name": "abc",
"thing": [{
"name": "123",
"list": ["one", "two"]
}]
}]
}]
This is two documents
[{
"a": [{
"name": "foo",
"thing": [{
"name": "bar",
"lyrics": ["1", "2", "3"]
}]
}]
},
{
"a": [{
"name": "abc",
"thing": [{
"name": "123",
"list": ["one", "two"]
}]
}]
}]
You can get stats on of a collection like so
db.test.stats()
"count" will tell you how many documents are there.
Edit: To add to this, in your collection "test" a document has 1 field, which is "a" and is of type array that holds objects (documents). It has 2 array elements
First
{
"name": "foo",
"thing": [{
"name": "bar",
"lyrics": ["1", "2", "3"]
}]
}
Second
{
"name": "abc",
"thing": [{
"name": "123",
"list": ["one", "two"]
}]
}
Everything inside curly braces {..}, including the braces themselves, is a one single document, i.e. the whole your database contains only one document that you receive for any matching query. To receive the desired result, you have to re-write your JSON document as an array of documents inside square braces [..].

Perl: Combine two JSONs

I am looking for help/guidance to combine multiple JSON into 1 JSON based on a node in PERL. For example here are the two JSON content that I want to combine.
JSON #1:
{
"title": "All",
"lastModified": "2017-04-11T00:00:00.000+0000",
"users": [{
"name": "Alpha One",
"title": "Security Chief",
"locations": [{"id": "730WLCS"}, {"id": "943MCS"}]
},
{
"name": "Alpha Two",
"title": "Security Manager"
}
]
}
JSON #2:
{
"title": "All",
"lastModified": "2017-04-11T00:00:00.000+0000",
"users": [{
"name": "Beta One",
"title": "Architect",
"locations": [{"id": "730WLCS"}]
}
]
}
RESULT JSON :
{
"title": "All",
"lastModified": "2017-04-11T00:00:00.000+0000",
"users": [{
"name": "Alpha One",
"title": "Security Chief",
"locations": [{"id": "730WLCS"}, {"id": "943MCS"}]
},
{
"name": "Alpha Two",
"title": "Security Manager"
},
{
"name": "Beta One",
"title": "Architect",
"locations": [{"id": "730WLCS"}]
}
]
}
Basically, I want to combine only the "users" node.
I tried to get the node using from_json and tried to push into an array, but it is not working.
Here is the code that I tried:
my $json_obj1 = from_json($json_txt1, {utf8 => 1});
my $json_obj2 = from_json($json_txt2, {utf8 => 1});
push(#myJSON, #{$json_obj1->{'users'}});
push(#myJSON, #{$json_obj2->{'users'}});
Any help is much appreciated.
Thank you.
my $json_obj1 = decode_json($json_txt1); # Same as from_json($json_txt1, {utf8 => 1})
my $json_obj2 = decode_json($json_txt2);
push #{ $json_obj2->{users} }, #{ $json_obj1->{users} };
If you want to remove duplicates , keeping the newer records (assuming $json_obj1 is the older state), you can use the following:
my %seen;
#{ $json_obj2->{users} } =
grep !$seen{$_->{name}}++,
#{ $json_obj2->{users} },
#{ $json_obj1->{users} };

PowerShell- Merging JSON files

How to copy the objects of one array of a JSON file to an array of another JSON file using PowerShell? For Example I have one JSON file like:
"type": "Employee",
"Properties": [
{
"Name": "Raj",
"Id": "18111",
"email": "emp1#company.com",
"Position": "Manager",
"DateOfJoining": "16.10.14",
}
],
"Description": "Employee details"
and another JSON file as:
"type": "Employee",
"Properties": [
{
"Name": "Ram",
"Id": "44000",
"email": "emp2#company.com",
"Position": "Admin",
"DateOfJoining": "10.12.14",
},
{
"Name": "Paul",
"Id": "44002",
"email": "emp3#company.com",
"Position": "Programmer",
"DateOfJoining": "10.9.14",
},
],
"Description": "Employee details"
I want to copy the arrays from 1st JSON file to the 2nd JSON file.
You can try something like this:
$c1 = Convert-FromJson (gc file1.json -raw)
$c2 = Convert-FromJson (gc file2.json -raw)
$c3 = $c1.Properties + $c2.Properties
$c3 | ConvertTo-Json