jq - how to conditionally filter out objects

Viewed 896

I'm trying to vastly simplify a large JSON file, and part of that process is conditionally filtering out some of the objects. I have a series of conditions I'd like to apply, but I'm not able to get even a single condition to work properly.

I've been working with the jq documentation, but I'm not a pro developer so it's challenging to read it. I found an example of this in another stackoverflow thread, so I've been trying to adapt that.

My source JSON file, while large, is clean and well-formed. It's basically one flat array of objects. A few of the keys in the objects are arrays as well, but I'll be discarding most of those anyway. Below is a sample, showing the first object:

[
   {
      "object":"card",
      "id":"86bf43b1-8d4e-4759-bb2d-0b2e03ba7012",
      "oracle_id":"0004ebd0-dfd6-4276-b4a6-de0003e94237",
      "multiverse_ids":[
         15862
      ],
      "mtgo_id":15870,
      "mtgo_foil_id":15871,
      "tcgplayer_id":3094,
      "name":"Static Orb",
      "lang":"en",
      "released_at":"2001-04-11",
      "uri":"https://api.scryfall.com/cards/86bf43b1-8d4e-4759-bb2d-0b2e03ba7012",
      "scryfall_uri":"https://scryfall.com/card/7ed/319/static-orb?utm_source=api",
      "layout":"normal",
      "highres_image":true,
      "mana_cost":"{3}",
      "cmc":3.0,
      "type_line":"Artifact",
      "oracle_text":"As long as Static Orb is untapped, players can't untap more than two permanents during their untap steps.",
      "colors":[

      ],
      "color_identity":[

      ],
      "legalities":{
         "standard":"not_legal",
         "future":"not_legal",
         "historic":"not_legal",
         "pioneer":"not_legal",
         "modern":"not_legal",
         "legacy":"legal",
         "pauper":"not_legal",
         "vintage":"legal",
         "penny":"not_legal",
         "commander":"legal",
         "brawl":"not_legal",
         "duel":"legal",
         "oldschool":"not_legal"
      },
      "games":[
         "paper",
         "mtgo"
      ],
      "reserved":false,
      "foil":true,
      "nonfoil":true,
      "oversized":false,
      "promo":false,
      "reprint":true,
      "variation":false,
      "set":"7ed",
      "set_name":"Seventh Edition",
      "set_type":"core",
      "collector_number":"319",
      "digital":false,
      "rarity":"rare",
      "flavor_text":"The warriors fought against the paralyzing waves until even their thoughts froze in place.",
      "card_back_id":"0aeebaf5-8c7d-4636-9e82-8c27447861f7",
      "artist":"Terese Nielsen",
      "artist_ids":[
         "eb55171c-2342-45f4-a503-2d5a75baf752"
      ],
      "illustration_id":"6f8b3b2c-252f-4f95-b621-712c82be38b5",
      "border_color":"white",
      "frame":"1997",
      "full_art":false,
      "textless":false,
      "booster":true,
      "story_spotlight":false,
      "edhrec_rank":1836,
      "prices":{
         "usd":"17.07",
         "usd_foil":"72.02",
         "eur":"10.73",
         "tix":"0.79"
      },
      "related_uris":{
         "gatherer":"https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=15862",
         "tcgplayer_decks":"https://decks.tcgplayer.com/magic/deck/search?contains=Static+Orb\u0026page=1\u0026utm_campaign=affiliate\u0026utm_medium=api\u0026utm_source=scryfall",
         "edhrec":"https://edhrec.com/route/?cc=Static+Orb",
         "mtgtop8":"https://mtgtop8.com/search?MD_check=1\u0026SB_check=1\u0026cards=Static+Orb"
      }
   }
]

First, I'm attempting to add a condition which will remove objects where the key "reprint" has the value true. This is what I've got so far:

curl -s https://archive.scryfall.com/bulk-data/default-cards/default-cards-20200529170427.json | jq .[] - "map(select(.reprint[] | contains (\"true\")))" > reprints_removed.json

But I keep getting this error:

jq: error: Could not open file map(select(.reprint[] | contains ("true"))): No such file or directory

Once I've got that working, I'd like to start using compound conditions. So, for instance, next I'll remove objects where either the key "reprint" is "true" or the key "border_color" is "silver".

Where am I going wrong?

1 Answers

The value of .reprint in each of the objects in the top-level array is strictly boolean, as can be seen by running:

jq 'map(.reprint)|unique'

So an efficient way to select the objects for which .reprint is false is to use the filter:

map(select(.reprint == false))

This will preserve the array structure. If you just want the JSON objects as a stream, you could write:

.[] | select(.reprint == false)

Since .reprint is strictly boolean, there are various equivalent formulations of the condition.

Negation

If .reprint were multi-valued, then to exclude the objects for which .reprint == true you could use negation:

.[] | select(.reprint == true | not)

Notice that in jq, not is a 0-ary filter -- it has no argument.

Compound conditions

remove objects where either the key "reprint" is "true" or the key "border_color" is "silver".

map(select( (.reprint == true or .border_color == "silver") | not))
Related