4

I have the following geojson file:

{
    "type": "FeatureCollection",
    "features": [{
            "type": "Feature",
            "properties": {
                "LINE": "RED",
                "STATION": "Harvard"
            },
            "geometry": {
                "type": "Point",
                "coordinates": [-71.118906072378209, 42.37402923068516]
            }
        },
        {
            "type": "Feature",
            "properties": {
                "LINE": "RED",
                "STATION": "Ashmont"
            },
            "geometry": {
                "type": "Point",
                "coordinates": [-71.063430144389983, 42.283883546225319]
            }
        }
    ]
}

I would like to append the second object within the "features" array to the end of it, creating 3 total objects. Using the below snippet errors out with "array ([{"type":"F...) and object ({"type":"Fe...) cannot be added". Is there a way to do this using jq without hardcoding the key:value pairs as seen here?

cat red_line_nodes.json | jq '.features |= . + .[length-1]' > red_line_nodes_2.json
Inian
  • 80,270
  • 14
  • 142
  • 161
m.brocks
  • 43
  • 5
  • What exactly are you wanting to add to the array? – jordanm Feb 26 '18 at 07:16
  • I want to duplicate one of the existing objects and add it to the array. Previous answers I had found on SO only show how to add a new object by typing in the various keys and values; what I want to know is if its possible to add in a new object using a reference to the existing file. – m.brocks Feb 26 '18 at 07:35
  • @m.brocks: Removed the duplicate tag complying to your above comment – Inian Feb 26 '18 at 08:00

2 Answers2

4

Short jq solution:

jq '.features |= . + [.[-1]]' red_line_nodes.json

The output:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "LINE": "RED",
        "STATION": "Harvard"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          -71.11890607237821,
          42.37402923068516
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "LINE": "RED",
        "STATION": "Ashmont"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          -71.06343014438998,
          42.28388354622532
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "LINE": "RED",
        "STATION": "Ashmont"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          -71.06343014438998,
          42.28388354622532
        ]
      }
    }
  ]
}
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
1

For reference, an alternative to using |= . + ... is to use +=. In your case, however, you would have to write:

.features += [.features[-1]]

so it's no shorter.

peak
  • 105,803
  • 17
  • 152
  • 177
  • but how come that it does work? In `|=` the "context" from left side of operator is array, thus you have to address that array on right side of operator using just `.` While here you have to use `.features` on both sides of `+=` operator. What is the explanation of that? – Martin Mucha Aug 18 '20 at 07:44
  • @MartinMucha - `(FOO += BAR)` has the semantics of `. as $in | (FOO += ($in|BAR))` – peak Aug 18 '20 at 14:50
  • thanks! Not that I actually understand that (which still makes me laugh, that I'd expect to be surprised less and less as I learn jq, not otherwise). Let me try to interpret that. 1. I save current context into variable. 2. since `|+` is IIRC `|= . +) ` I will update FOO reachable from current context by adding to it current context filtered by BAR. Ah, yes, great, that's exactly what you did here and it explains the difference. Ok, I think I understand it now. Thanks again. (keeping this text here,it help me understand it writing it, it might work equally for reading) – Martin Mucha Aug 19 '20 at 13:29