skip to Main Content

I would like to print {score: score_value, id: id_value}, by using jq from the following json script (only a small part is here for introduction), I tried jq '[score: .hits.hits[]._score, id: .hits.hits[]._id]' and also jq '{.hits.hits[]._score, .hits.hits[]._id}', but both have compile error.

{
  "took" : 17,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 100,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "ff0",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "server_id" : 86,
          "@timestamp" : "2023-03-01T11:09:23.474948161Z",

3

Answers


  1. To get a stream of elements (i.e. multiple JSON documents):

    .hits.hits[] | { score: ._score, id: ._id }
    

    Output:

    {
      "score": 1,
      "id": "1"
    }
    

    Or to get a single JSON array:

    .hits.hits | map({ score: ._score, id: ._id })
    

    Output:

    [
      {
        "score": 1,
        "id": "1"
      }
    ]
    
    Login or Signup to reply.
  2. A solution using with_entries:

    .hits.hits[] | with_entries(select(.key == "_score" or .key == "_id"))
    

    though the _score and _id keys may not appear in the order you want (eg you may want the _score at the top of the JSON). If this doesn’t matter, this is another possible solution.

    Login or Signup to reply.
  3. I tried jq '[score: .hits.hits[]._score, id: .hits.hits[]._id]' and also jq '{.hits.hits[]._score, .hits.hits[]._id}', but both have compile error.

    You swapped the symbols for arrays ([...]) and objects ({...}).

    As in any other language, a JavaScript array is a collection of items (presumably of the same type but this is not required), listed in a certain order. In the JavaScript source code or as JSON they are separated by commas and enclosed in square brackets ([ and ]). They do not have names/labels and are identified by their index (starting with 0).
    jq '.hits.hits' extracts from the input JSON an array (of objects); the JSON fragment that you posted in the question shows only a fragment of the first item of the array.

    A JavaScript object is a collection of properties that have values. The order of the properties does not matter. In JavaScript code (or in JSON, which is a valid fragment of JavaScript code), an object is represented as pairs of (property, value) joined by :. The pairs are joined by commas (,) and all the pairs are wrapped in curly braces ({ and }). The JSON in the question encodes an object having properties took, timed_out and so one.

    In order to be correct, your attempts should be like:

    jq '[ .hits.hits[]._score, .hits.hits[]._id ]'
    

    or:

    jq '{ score: .hits.hits[]._score, id: .hits.hits[]._id }'
    

    They probably do not extract what you want but at least they are correct and extract some data.

    In order to extract the data you need, you can try something like this:

    jq '[.hits.hits[] | { id: ._id, score: ._score }]'
    

    How it works

    [                                # wrap the results of the next filters into an array
      .hits.hits                     # extract the property `hits` of the property `hits`...
                                     # ... from input (it is an array)
      []                             # split the array to individual items
      |                              # pass the output of the previous filter as input...
                                     # ... to the next filter
      { id: ._id, score: ._score }   # extract the properties `_id` and `_score` from...
                                     # ... the current input (`.`) and produce an object...
                                     # ... whose properties are `id` and `score`
    ]                                # close the opening `[` that starts the `jq` program
    

    Note that [] (or | .[]) splits an input array into items and feeds the next filter multiple input objects. They are processed individually by the next filter and collected back into an array by the wrapping square brackets ([...]).

    An alternative way to get the same result is to use the map() filter. It runs the filter passed as argument against each item of the input array and collects the results into a new array.

    jq '.hits.hits | map({ id: ._id, score: ._score })'
    

    Technically it is the same as:

    jq '.hits.hits | [.[] | { id: ._id, score: ._score }]'
    

    Check these solutions online.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search