【问题标题】:jq - how to conditionally filter out objectsjq - 如何有条件地过滤掉对象
【发布时间】:2020-05-30 14:23:52
【问题描述】:

我正在尝试极大地简化一个大型 JSON 文件,并且该过程的一部分是有条件地过滤掉一些对象。我有一系列条件要申请,但我连一个条件都无法正常工作。

我一直在使用 jq 文档,但我不是专业开发人员,因此阅读它很有挑战性。我在另一个 stackoverflow 线程中找到了一个例子,所以我一直在尝试适应它。

我的源 JSON 文件虽然很大,但干净且格式良好。它基本上是一个平面的对象数组。对象中的一些键也是数组,但无论如何我都会丢弃其中的大部分。下面是一个示例,显示了第一个对象:

[
   {
      "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"
      }
   }
]

首先,我尝试添加一个条件,该条件将删除键“reprint”值为真的对象。这是我到目前为止所得到的:

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

但我不断收到此错误:

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

一旦我完成了这项工作,我想开始使用复合条件。因此,例如,接下来我将删除键“reprint”为“true”或键“border_color”为“silver”的对象。

我哪里错了?

【问题讨论】:

    标签: json select jq


    【解决方案1】:

    顶层数组中每个对象的.reprint值都是严格的布尔值,可以通过运行看到:

    jq 'map(.reprint)|unique'
    

    因此,选择 .reprint 为 false 的对象的一种有效方法是使用过滤器:

    map(select(.reprint == false))
    

    这将保留数组结构。如果您只想将 JSON 对象作为流,您可以编写:

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

    由于 .reprint 是严格的布尔值,因此有各种等价的条件表述。

    否定

    如果 .reprint 是多值的,那么要排除 .reprint == true 可以使用否定的对象:

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

    请注意,在 jq 中,not 是一个 0 元过滤器——它没有参数。

    复合条件

    删除键“reprint”为“true”或键“border_color”为“silver”的对象。

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

    【讨论】:

    • 感谢您的快速回复!我把它们放在一起,使用流版本,转义引号和括号,并尝试运行:curl -s https://archive.scryfall.com/bulk-data/default-cards/default-cards-20200529170427.json | jq .[] | select\( \(.reprint == true or .border_color == \"silver\"\) | not\) > test.json。但我收到了这个错误:Command 'not)' not found, did you mean: command 'note' from deb note Try: sudo apt install <deb name> select(: command not found
    • 如果你把 jq 程序放到一个文件中,比如说 program.jq,然后和 jq -f program.jq 一起使用,你会发现会容易得多
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-04
    • 1970-01-01
    • 1970-01-01
    • 2020-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多