Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merge two json objects

I have the following inputs - 2 json files one is the base one and the second contains the same properties but the different values, I'd like to merge that objects.

For example:

{
  a:{
    b:"asda"
  }
  c: "asdasd"
}

And the second file:

{
  a:{
   b:"d"
  }
}

And the result should be like this:

{a:{b:"d"},c:"asdasd"}

Is that is possible with powershell?

like image 604
Ihor Korotenko Avatar asked Aug 07 '17 14:08

Ihor Korotenko


3 Answers

Join (Join-Object) is not a built-in CmdLet

This is an extension of @Mark's answer which also recurses through child objects.

function merge ($target, $source) {
    $source.psobject.Properties | % {
        if ($_.TypeNameOfValue -eq 'System.Management.Automation.PSCustomObject' -and $target."$($_.Name)" ) {
            merge $target."$($_.Name)" $_.Value
        }
        else {
            $target | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $_.Value -Force
        }
    }
}

merge $Json1 $Json2

$Json1
like image 85
waxingsatirical Avatar answered Nov 17 '22 21:11

waxingsatirical


$Json1 | Join $Json2 -Merge {$Right.$_} | ConvertTo-Json (see update below)

($Json1 ConvertFrom-Json) | Merge ($Json2 ConvertFrom-Json) | ConvertTo-Json

Result:

{
    "c":  "asdasd",
    "a":  {
              "b":  "d"
          }
}

You might consider not to overwrite the left value:

($Json1 ConvertFrom-Json) | Join ($Json2 ConvertFrom-Json) | ConvertTo-Json

In that case the result will be:

{
    "c":  "asdasd",
    "a":  [
              {
                  "b":  "asda"
              },
              {
                  "b":  "d"
              }
          ]
}

For details see: https://stackoverflow.com/a/45483110/1701026


Update 2019-11-16
The -Merge parameter has been depleted and divided over the -Discern and -Property parameters (sorry for the breaking change). The good news is that the default parameter settings for an object merge are accommodated in a proxy command named Merge-Object (alias Merge) which simplifies the concerned syntax to just: $Object1 | Merge $Object2. For details, see readme or embedded help.

like image 34
iRon Avatar answered Nov 17 '22 22:11

iRon


If you know the names of the elements (per your example above), you could do it explicitly like this:

$Json1 ='{
  a: {
    b:"asda"
  },
  c: "asdasd"
}
' | ConvertFrom-Json

$Json2 = '{
  a:{
   b:"d"
  }
}
' | ConvertFrom-Json


$Json1.a = $Json2.a

Result:

$Json1 | ConvertTo-Json

{
    "a":  {
              "b":  "d"
          },
    "c":  "asdasd"
}

If you're looking for something that will merge the two without knowing the explicit key name, you could do something like the following. This will essentially overwrite any properties in the first Json with those from the second Json, where they are duplicated at the first level (it won't seek matches in the nested properties and again this is an overwrite not a merge):

$Json2.psobject.Properties | ForEach-Object {
    $Json1 | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $_.Value -Force
}
like image 38
Mark Wragg Avatar answered Nov 17 '22 22:11

Mark Wragg