Ckym
Ckym

Reputation: 15

Find and replace json in a file using jq

I am new at using jq and could use help with the following...

In essence, I am trying to "find and replace" a block of json in a file using a bash script.

I have a file called docs.json to where I retrieved a set of doc entries:

{
    "number_of_docs": "1000",
    "docs": [{
    {
        "_id": "000001",
        "_rev": "0",
        "_content": "abcdefg"
    },
    {
        "_id": "000002",
        "_rev": "0",
        "_content": "hijklmn",
        "_attachments": {
            "image1.png": {
                "content_type": "image/png"
                ...
            }
        }
    },
    {
        "_id": "000003",
        "_rev": "0",
        "_content": "opqrstuv"
    }]
}

And I'm trying to replace all the doc entries (the entire block, not just the value of the keys) that have "_attachments" with a new block of json that is stored in a variable named "doc":

{
    "_id": "000002_masked",
    "_rev": "0",
    "_content": "[Document content has been masked for confidentiality.]",
    "_attachments": {
        "confidential.png": {
            "content_type": "image/png"
            ...
        }
    }
}

Is what I'm trying to do possible with jq and running from within a bash script?

Thank you for the help and tips, in advance.

Upvotes: 0

Views: 3649

Answers (2)

jq170727
jq170727

Reputation: 14725

If you cannot use --argjson you could use the -s slurp option along with a filter such as

  .[0] as $new
| .[1]
| ( .docs[] | select(has("_attachments")) ) = $new

if the above is in filter.jq, your new document in new.json and your data contains a single object as you describe in docs.json then

jq -M -s -f filter.jq new.json docs.json

will produce

{
  "number_of_docs": "1000",
  "docs": [
    {
      "_id": "000001",
      "_rev": "0",
      "_content": "abcdefg"
    },
    {
      "_id": "000002_masked",
      "_rev": "0",
      "_content": "[Document content has been masked for confidentiality.]",
      "_attachments": {
        "confidential.png": {
          "content_type": "image/png"
        }
      }
    },
    {
      "_id": "000003",
      "_rev": "0",
      "_content": "opqrstuv"
    }
  ]
}

Note - I don't have jq-1.3 so I'm only able to verify this with jq-1.5 but I believe this should work with jq-1.3

Upvotes: 0

chepner
chepner

Reputation: 532418

The key is to select the documents that have the _attachments key, then replace them with the |= operator.

jq --argjson new "$doc" '(.docs[]| select(has("_attachments"))) |= $new' docs.json

--argjson is used to pass the value of $doc into the filter as a raw JSON value.

Upvotes: 3

Related Questions