steven lee
steven lee

Reputation: 21

JQ:How can i update the value of json by jq?

I have a json file like this :

{"users":{"347793":"user1"}}
{"users":{"6560536":"user2"}}
{"users":{"6637901":"user3"}}
{"users":{"5850517":"user4"}}
{"users":{"2907509":"user5"}}
{"users":{"6611743":"user6"}}
{"users":{"6535592":"user7"}}
{"users":{"5586286":"user8"}}
{"users":{"2484439":"user9"}}
{"messages":{"id":"id1","owner":{"id":"347793","type":"user"},"otherUser":{"id":"6560536","type":"user"}}}
{"messages":{"id":"id2","owner":{"id":"6637901","type":"user"},"otherUser":{"id":"6560536","type":"user"}}}
{"messages":{"id":"id3","owner":{"id":"2907509","type":"user"},"otherUser":{"id":"2484439","type":"user"}}}
{"messages":{"id":"id4","owner":{"id":"347793","type":"user"},"otherUser":{"id":"2907509","type":"user"}}}
{"messages":{"id":"id5","owner":{"id":"5850517","type":"user"},"otherUser":{"id":"5850517","type":"user"}}}
{"messages":{"id":"id6","owner":{"id":"5586286","type":"user"},"otherUser":{"id":"347793","type":"user"}}}

I want to get the output file like this, to change the owner's type to the user's name:

{"users":{"347793":"user1"}}
{"users":{"6560536":"user2"}}
{"users":{"6637901":"user3"}}
{"users":{"5850517":"user4"}}
{"users":{"2907509":"user5"}}
{"users":{"6611743":"user6"}}
{"users":{"6535592":"user7"}}
{"users":{"5586286":"user8"}}
{"users":{"2484439":"user9"}}
{"messages":{"id":"id1","owner":{"id":"347793","type":"user1"},"otherUser":{"id":"6560536","type":"user2"}}}
{"messages":{"id":"id2","owner":{"id":"6637901","type":"user3"},"otherUser":{"id":"6560536","type":"user2"}}}
{"messages":{"id":"id3","owner":{"id":"2907509","type":"user5"},"otherUser":{"id":"2484439","type":"user9"}}}
{"messages":{"id":"id4","owner":{"id":"347793","type":"user1"},"otherUser":{"id":"2907509","type":"user5"}}}
{"messages":{"id":"id5","owner":{"id":"5850517","type":"user4"},"otherUser":{"id":"5850517","type":"user4"}}}
{"messages":{"id":"id6","owner":{"id":"5586286","type":"user8"},"otherUser":{"id":"347793","type":"user10"}}}

I have no idea to do this, I try some code but it not works.

jq -c '.messages[] as $message| $message.owner.type|=.users[]|select(.id==$message.owner.id).name'

Upvotes: 1

Views: 212

Answers (2)

peak
peak

Reputation: 116670

If the number of "messages" is very large, then it might be better to process each one separately, to avoid having to read them all into memory.

At any rate, the following illustrates how one can use jq to read in one file to construct a dictionary, and to process a second file on a line-by-line basis.

Let's suppose we have partitioned the JSON into two files (users.json and messages.json), and that the following lines are in process.jq:

# Apply f to composite entities recursively, and to atoms
def walk(f):
  . as $in
  | if type == "object" then
      reduce keys[] as $key
        ( {}; . + { ($key):  ($in[$key] | walk(f)) } ) | f
  elif type == "array" then map( walk(f) ) | f
  else f
  end;

($users | map(.users) | add) as $dict
| walk(if type == "object" and .type == "user"
       then .type = $dict[.id]
       else .
       end)

(If your jq already has walk/1, then its definition can be omitted.)

Then the following command can be used to process the messages:

$ jq --slurpfile users users.json -f process.jq messages.json

Upvotes: 1

Jeff Mercado
Jeff Mercado

Reputation: 134811

Your data has no structure, it'll be easier if you gave it some.

{ users: map(.users // empty), messages: map(.messages // empty) }

When you slurp that file up with this, it'll give you this:

{
  "users": [
    { "347793": "user1" },
    { "6560536": "user2" },
    { "6637901": "user3" },
    { "5850517": "user4" },
    { "2907509": "user5" },
    { "6611743": "user6" },
    { "6535592": "user7" },
    { "5586286": "user8" },
    { "2484439": "user9" }
  ],
  "messages": [
    {
      "id": "id1",
      "owner": { "id": "347793", "type": "user" },
      "otherUser": { "id": "6560536", "type": "user" }
    },
    {
      "id": "id2",
      "owner": { "id": "6637901", "type": "user" },
      "otherUser": { "id": "6560536", "type": "user" }
    },
    {
      "id": "id3",
      "owner": { "id": "2907509", "type": "user" },
      "otherUser": { "id": "2484439", "type": "user" }
    },
    {
      "id": "id4",
      "owner": { "id": "347793", "type": "user" },
      "otherUser": { "id": "2907509", "type": "user" }
    },
    {
      "id": "id5",
      "owner": { "id": "5850517", "type": "user" },
      "otherUser": { "id": "5850517", "type": "user" }
    },
    {
      "id": "id6",
      "owner": { "id": "5586286", "type": "user" },
      "otherUser": { "id": "347793", "type": "user" }
    }
  ]
}

Then doing the replacement should be easier.

(.users | add) as $users
    | (.messages[].owner |= (.type = $users[.id]))
    | (.messages[].otherUser |= (.type = $users[.id]))

Then if for whatever reason you want to go back to your other structure, then it should be easy (but I wouldn't recommend it).

{ users: .users[] }, { messages: .messages[] }

Upvotes: 0

Related Questions