Merging two json files into one? [duplicate] - json

This question already has answers here:
Merge two json objects
(3 answers)
Closed 2 months ago.
I have two .Json files I need to merge into one .Json file:
The first file start.json looks like this:
{
"MOUSE GESTURE L Start": {
"prefix": "MOUSE GESTURE L Start To Start",
"body": [
"MG_Start()"
],
"description": "Start Cursor back to its start"
}
}
The second file end.json looks like this:
{
"MOUSE GESTURE L Move To end": {
"prefix": "MOUSE GESTURE L Move To end",
"body": [
"MG_Move()"
],
"description": "Move Cursor back to its end"
}
}
The Expected out I am aiming for is:
{
"MOUSE GESTURE L Start": {
"prefix": "MOUSE GESTURE L Start To Start",
"body": [
"MG_Start()"
],
"description": "Start Cursor back to its start"
}
"MOUSE GESTURE L Move To end": {
"prefix": "MOUSE GESTURE L Move To end",
"body": [
"MG_Move()"
],
"description": "Move Cursor back to its end"
}
}
I have tried:
$Jstart = (Get-Content .\start.json -Raw) | ConvertFrom-Json
$JEnd = (Get-Content .\end.json -Raw) | ConvertFrom-Json
$Hash = [PSCustomObject]#{
$Jstart = (Get-Content .\start.json -Raw) | ConvertFrom-Json
$JEnd = (Get-Content .\end.json -Raw) | ConvertFrom-Json
}
but I get a undesired jumbled output:
{
"#{MOUSE GESTURE L Start=}": {
"MOUSE GESTURE L Start": {
"prefix": "MOUSE GESTURE L Start To Start",
"body": "MG_Start()",
"description": "Start Cursor back to its start"
}
},
"#{MOUSE GESTURE L Move To end=}": {
"MOUSE GESTURE L Move To end": {
"prefix": "MOUSE GESTURE L Move To end",
"body": "MG_Move()",
"description": "Move Cursor back to its end"
}
}
}
I've tried variations but things just get worse.
Any ideas on how I can get this right? Thank you
EDIT:
#Santiago Squarzon
While solution works for the example I provided, I am getting problems trying to adapt it to my code.
The prblem I am having is, if one of the .Json files happens to have more than one object in it, like this:
{
"MOUSE GESTURE L Move To end": {
"prefix": "MOUSE GESTURE L Move To end",
"body": [
"MG_Move()"
],
"description": "Move Cursor back to its end"
},
"Another Snippet": {
"prefix": "MOUSE GESTURE L Move To end",
"body": [
"MG_Move()"
],
"description": "Move Cursor back to its end"
}
}
Then $left.PSObject.Properties.Add($($right.PSObject.Properties)) failss, I get the error:
MethodException:
Cannot find an overload for "Add" and the argument count: "1".

Probably the easiest to go about this would be to append one object to the other:
$left = Get-Content .\start.json -Raw | ConvertFrom-Json
$right = Get-Content .\end.json -Raw | ConvertFrom-Json
foreach($prop in $right.PSObject.Properties) {
$left.PSObject.Properties.Add($prop)
}
$left | ConvertTo-Json -Depth 99
Resulting Json would look something like this:
{
"MOUSE GESTURE L Start": {
"prefix": "MOUSE GESTURE L Start To Start",
"body": [
"MG_Start()"
],
"description": "Start Cursor back to its start"
},
"MOUSE GESTURE L Move To end": {
"prefix": "MOUSE GESTURE L Move To end",
"body": [
"MG_Move()"
],
"description": "Move Cursor back to its end"
}
}

Related

List inside JSON Powershell

I am trying to parse the following JSON into a PSCustomObject
[
{
"tags": [
{
"tagName": "Microsoft Teams"
},
{
"tagName": "Worldwide (Standard Multi-Tenant)"
},
{
"tagName": "General Availability"
},
{
"tagName": "Web"
},
{
"tagName": "Desktop"
}
],
"tagsContainer": {
"products": [
{
"tagName": "Microsoft Teams"
}
],
"cloudInstances": [
{
"tagName": "Worldwide (Standard Multi-Tenant)"
}
],
"releasePhase": [
{
"tagName": "General Availability"
}
],
"platforms": [
{
"tagName": "Web"
},
{
"tagName": "Desktop"
}
]
},
"id": 51230,
"title": "Microsoft Teams: New file sharing experience",
"description": "Streamline sharing with Microsoft Teams. You can now create a shareable link for any file stored in Teams and directly set the appropriate permissions. Additionally, you can also set permissions for files stored in SharePoint or OneDrive while composing a private chat or starting a channel conversation.",
"status": "Launched",
"moreInfoLink": "https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/rich-new-file-and-sharing-experiences-throughout-microsoft-365/ba-p/960129",
"publicRoadmapStatus": "Include this month",
"created": "2019-05-08T07:00:00",
"modified": "2022-01-13T00:05:19.663",
"publicDisclosureAvailabilityDate": "March CY2021",
"publicPreviewDate": ""
}
]
I have that JSON stored in a variable like this:
$RoadmapContent = Get-Content -Raw -Path ".\M365Roadmap_single.json" | ConvertFrom-Json
And this would be my PSCustomObject:
$RoadmapItems =[PSCustomObject]#{
Title = $($RoadmapContent.title)
Tags = $($RoadmapContent.tags)
}
I would like to have this tags in a single column, like this: Microsoft Teams, Worldwide (Standard Multi-Tenant), General Availability, Web, Desktop
I have tried to accomplish that (unsuccessfully) like this:
$RoadmapContent.Tags -join ";"
How can I parse this?
Many thanks!
Edit:
I can access the tags like this:
foreach ($tag in $RoadmapContent.tags) {Write-Host $Tag.tagName}
But cannot figure out how to use this in a PSCustomObject
Figured it out thanks to a comment in the original question, here's the full code:
$RoadmapContent = Get-Content -Raw -Path ".\M365Roadmap_single.json" | ConvertFrom-Json
$RoadmapItems =[PSCustomObject]#{
Title = $($RoadmapContent.title)
Tags = $($RoadmapContent.tags.tagname -join ', ')
}
$RoadmapItems

Add element outside of array to csv output

I have a JSON structure similar to this one:
{
"results": [
{
"title": "Page 1",
"content": {
"id": "11111"
}
},
{
"title": "Page 2",
"content": {
"id": "22222"
}
},
{
"title": "Page 3",
"content": {
"id": "33333"
}
}
],
"start": 0,
"limit": 25,
"size": 3,
"totalSize": 3,
"query": "Hello World"
}
The output I need is:
"Page 1","11111","Hello World"
"Page 2","22222","Hello World"
"Page 3","33333","Hello World"
I can get the elements from the array with:
cat my.json | jq -r '.results[] | [.title, .content.id] | #csv'
But how do I add the "query" element which is outside of the array to each line in the output?
I tried a bunch of options but I can't get it to work.
Use a little placeholder to store the value of .query and use it back when putting it in array
.query as $q | .results[] | [.title, .content.id, $q] | #csv
Or put them in separate arrays. The (...) around .results path ensures, you don't walk to the path below and still remain at the top level node path.
(.results[] | [.title, .content.id]) + [.query] | #csv

ConvertFrom-JSON won't accept convertto-json with children when working with WebServiceProxy

I am pulling data from an API using the New-WebServiceProxy in PowerShell 4.0 and then piping it out to a JSON file for review and import on another API service (same API version, etc, just a different host).
$tasklist.Taskconfig | ConvertTo-JSON-Depth 50 -As String | Out-File -FilePath $exportpath\$name.xml -Force
Gives me my XML containing the TaskConfig. In this case, TaskConfig is an object type automatically generated by the API I'm interfacing with. When I want to import the content I am using:
$taskconfig = (Get-Content "$taskjson") -join "`n" | ConvertFrom-Json
but when I run this it's unable to create the object. I assume this is because the JSON contains nested children, giving the error-
Cannot convert value "#{Name=plugindive; Value=;> Children=System.Object[]}" to type "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1rcleWeb_WebClientAPI_asmx_wsdl.TaskConfig". Error: "Cannot convert the "#{Name=plugindive; Value=;Children=System.Object[]}" value of type "System.Management.Automation.PSCustomObject" to type "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1rcleWeb_WebClientAPI_asmx_wsdl.TaskConfig"."
I've tried explictly stating the type of object:
$taskconfig = [Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1rcleWeb_WebClientAPI_asmx_wsdl.TaskConfig](Get-Content "$taskjson" | Out-string | ConvertFrom-Json)
as well as creating the object then trying to add the children from my JSON -
$taskconfig.children = $json.children
But these all fail in the same way.
I don't seem to get this same issue in PowerShell 5.0 interestingly enough, but I can't verify why - is there another way to approach this?
Added example JSON below
{"Name": "plugindive",
"Value": null,
"Children": [{
"Name": "auto",
"Value": "False",
"Children": [
]
},
{
"Name": "categories",
"Value": null,
"Children": [{
"Name": "Module Z",
"Value": "False",
"Children": [
]
},
{
"Name": "Module A",
"Value": "False",
"Children": [
]
},
{
"Name": "Module B",
"Value": "False",
"Children": [
]
},
{
"Name": "Module C",
"Value": "False",
"Children": [
]
}
]
}
]
}
It seems as if this doesn't work in PowerShell v3.0, so I simply ended up making posts with the explicit XML directly, rather than converting to JSON.

Merge two complex JSON objects (using jq)

I'm trying to replace objects in a complex JSON object. It seemed that the tool jq could be offering the perfect solution, but I'm really struggling with the right choice / chain of filters.
I have a complete configuration JSON object which looks like this (has some more keys in it, shortened it for illustration):
{
"some-array": [
{
"name": "foo",
"attr": "value"
},
{
"name": "foo bar",
"attr": "value"
},
{
"name": "foo bar baz",
"attr": "value"
}
],
"some-other-array": []
}
Now I have another object containing an array with updated objects which I need to merge with the full configuration in some way. I need to find the nested objects by name, add it if it does not exist yet and replace it if it does exist.
{
"some-array": [
{
"name": "foo",
"attr": "new-value",
"new-attrib": "new-value"
},
{
"name": "foo bar",
"attr": "new-value"
}
]
}
So, with the above example, my expected result would be:
{
"some-array": [
{
"name": "foo",
"attr": "new-value",
"new-attrib": "new-value"
},
{
"name": "foo bar",
"attr": "new-value"
},
{
"name": "foo bar baz",
"attr": "value"
}
],
"some-other-array": []
}
I already tried select(."some-array"[].name == "foo") to begin with and a few other things as a jq filter, but I'm struggling to move forward here and would really appreciate some inspiration / an actual solution.
Can anyone tell me if what I'm trying to achieve is actually possible with jq or do I have to find another solution?
Here is a solution to the updated problem. This solution assumes that the names are string-valued. It relies on two helper functions:
# array-to-hash
def a2h(f): reduce .[] as $x ({}; . + {($x | f): $x});
# hash-to-array
def h2a: . as $in | reduce keys_unsorted[] as $k ([]; . + [$in[$k]]);
The first of these creates a "hash" based on an input array, and the second implements the inverse operation.
With these helper functions, the solution can be written:
.["some-array"] |= (a2h(.name) + ($update|.["some-array"] | a2h(.name)) | h2a)
where $update is the "new" value. This solution relies on the "right-dominance" of object-addition.
Output
For the given example, the output is:
{
"some-array": [
{
"name": "foo",
"attr": "new-value",
"new-attrib": "new-value"
},
{
"name": "foo bar",
"attr": "new-value"
},
{
"name": "foo bar baz",
"attr": "value"
}
],
"some-other-array": []
}
Yes, it's possible, and in fact quite easy under various interpretations of the problem as originally stated.
The following solves the the problem as it was originally stated, with "it" being interpreted as .["some-array"] rather than its constituents.
Assuming $update holds the object with the updated information as shown, the update could be performed using this filter:
.["some-array"] = ($update | .["some-array"])
There are many ways to endow $update with the desired value.

Not able to Iterate through JSON response object with JQ in Unix shell

I am trying to iterate through a JSON object in UNIX, where the idea is to pickup different values and append it to a string and forward it as a syslog. Below is the code.
//picking up the length of Object
count=$(jq '.content | length' red)
#echo $count
enter code here
for((i=0;i<$count;i++))
do
echo "MY VALUE OF I"
echo $i
//THE BELOW LINE GIVES ERROR UPON USAGE of $i
id="$(cat red | jq '.content[$i].id')"
source=$(cat red | jq '.content[$i].entitySummary.source')
.
.
#syslogString="ID=$id SOURCE=$source SUMMARY=$summaryText TITLE=$title DESCRIPTION=$description SEVERITY=$severity MITIGATION=$mitigation IMPACT=$impactDescrip$
echo $id
echo "value of ID ($id)"
I am receiving compilation error with content[$i] and cant get a workaround the same.
The response class looks like this:
Page {
content ( array[ ClientIncident ] )
The list of results that make up the page. The number of elements should be less than or equal to the currentPage size.
currentPage ( Pagination )
Size and offset information about the current page.
total ( integer )
The total number of results found. If there are a large number of results, this may be an estimate. Accuracy should improve as the page approaches the end of the resultset.
}
under content the JSON response looks as below:
{
"content": [
{
"id": 951653,
"version": 12,
"score": 100,
"entitySummary": {
"source": "somewebsite",
"summaryText": "someTEXT here",
"domain": "www.domian.com",
"sourceDate": "2014-12-19T17:00:00.000Z",
"type": "WEB_PAGE"
},
"type": "SomeTYPE",
"title": "some Title",
"description": "some description ",
"occurred": "2014-12-19T17:00:00.000Z",
"verified": "2014-12-19T17:17:22.326Z",
"tags": [
{
"id": 424,
"name": "Data Breach or Compromise",
"type": "IMPACT_EFFECTS"
},
{
"id": 1064,
"name": "United States",
"type": "TARGET_GEOGRAPHY"
},
],
"severity": "MEDIUM",
"clientId": "NET",
"alerted": "2014-12-19T17:39:55.500Z",
"mitigation": "MititgationINFO",
"impactDescription": "IMpact description": 0
},
{
"id": 951174,
"version": 8,
"score": 100,
"entitySummary": {
Ok I got the answer for this.
We can use the below syntax to make is work in the for loop.
id=$(cat red | jq '.content['${i}'].id')