2015-02-18 8 views
5

Sto lavorando con The AWS Command Line Interface for DynamoDB.Come semplificare aws L'output JSON della query DynamoDB dalla riga di comando?

Quando eseguiamo una query su un articolo, otteniamo un output JSON molto dettagliato. È possibile ottenere qualcosa di simile (è stato costruito dal get-item in modo da essere quasi esaustivo (il tipo NULL è stato omesso) aws command line help:

{ 
    "Count": 1, 
    "Items": [ 
     { 
      "Id": { 
       "S": "app1" 
      }, 
      "Parameters": { 
       "M": { 
        "nfs": { 
         "M": { 
          "IP" : { 
           "S" : "172.16.0.178" 
          }, 
          "defaultPath": { 
           "S": "/mnt/ebs/" 
          }, 
          "key": { 
           "B": "dGhpcyB0ZXh0IGlzIGJhc2U2NC1lbmNvZGVk" 
          }, 
          "activated": { 
           "BOOL": true 
          } 
         } 
        }, 
        "ws" : { 
         "M" : { 
          "number" : { 
           "N" : "5" 
          }, 
          "values" : { 
           "L" : [ 
            { "S" : "12253456346346"}, 
            { "S" : "23452353463464"}, 
            { "S" : "23523453461232"}, 
            { "S" : "34645745675675"}, 
            { "S" : "46456745757575"} 
           ] 
          } 
         } 
        } 
       } 
      }, 
      "Oldtypes": { 
       "typeSS" : {"SS" : ["foo", "bar", "baz"]}, 
       "typeNS" : {"NS" : ["0", "1", "2", "3", "4", "5"]}, 
       "typeBS" : {"BS" : ["VGVybWluYXRvcgo=", "VGVybWluYXRvciAyOiBKdWRnbWVudCBEYXkK", "VGVybWluYXRvciAzOiBSaXNlIG9mIHRoZSBNYWNoaW5lcwo=", "VGVybWluYXRvciA0OiBTYWx2YXRpb24K","VGVybWluYXRvciA1OiBHZW5lc2lzCg=="]} 
      } 
     } 
    ], 
    "ScannedCount": 1, 
    "ConsumedCapacity": null 
} 

C'è un modo per ottenere una produzione più semplice per la parte Items? come questo:..

{ 
    "ConsumedCapacity": null, 
    "Count": 1, 
    "Items": [ 
     { 
      "Id": "app1", 
      "Parameters": { 
       "nfs": { 
        "IP": "172.16.0.178", 
        "activated": true, 
        "defaultPath": "/mnt/ebs/", 
        "key": "dGhpcyB0ZXh0IGlzIGJhc2U2NC1lbmNvZGVk" 
       }, 
       "ws": { 
        "number": 5, 
        "values": ["12253456346346","23452353463464","23523453461232","34645745675675","46456745757575"] 
       } 
      }, 
      "Oldtypes": { 
       "typeBS": ["VGVybWluYXRvcgo=", "VGVybWluYXRvciAyOiBKdWRnbWVudCBEYXkK", "VGVybWluYXRvciAzOiBSaXNlIG9mIHRoZSBNYWNoaW5lcwo=", "VGVybWluYXRvciA0OiBTYWx2YXRpb24K", "VGVybWluYXRvciA1OiBHZW5lc2lzCg=="], 
       "typeNS": [0, 1, 2, 3, 4, 5], 
       "typeSS": ["foo","bar","baz"] 
      } 
     } 
    ], 
    "ScannedCount": 1 
} 

Non c'è niente di utile nel dynamodb - AWS CLI 1.7.10 documentation

Dobbiamo ottenere il risultato dalla riga di comando che sono disposto a utilizzare altri strumenti da riga di comando li ke jq se necessario, ma tale mappatura jq sembra complicata per me.


Update 1: jq soluzione basata (con l'aiuto di risposta di DanielH)

Con jq è facile, ma non abbastanza bella, si può fare qualcosa di simile:

$> aws dynamodb query --table-name ConfigCatalog --key-conditions '{ "Id" : {"AttributeValueList": [{"S":"app1"}], "ComparisonOperator": "EQ"}}' | jq -r '.Items[0].Parameters.M."nfs#IP".S' 

Risultato sarà: 172.16.0.178

jq-r opzione gi ti mostra un output raw.


Aggiornamento 2: jq soluzione basata (con l'aiuto di @ jeff-mercado)

Ecco una versione aggiornata e commentata della funzione Jeff Mercado jq a unmarshall uscita DynamoDB. Essa vi darà i risultati attesi:

$> cat unmarshal_dynamodb.jq 
def unmarshal_dynamodb: 
    # DynamoDB string type 
    (objects | .S) 

    # DynamoDB blob type 
    // (objects | .B) 

    # DynamoDB number type 
    // (objects | .N | strings | tonumber) 

    # DynamoDB boolean type 
    // (objects | .BOOL) 

    # DynamoDB map type, recursion on each item 
    // (objects | .M | objects | with_entries(.value |= unmarshal_dynamodb)) 

    # DynamoDB list type, recursion on each item 
    // (objects | .L | arrays | map(unmarshal_dynamodb)) 

    # DynamoDB typed list type SS, string set 
    // (objects | .SS | arrays | map(unmarshal_dynamodb)) 

    # DynamoDB typed list type NS, number set 
    // (objects | .NS | arrays | map(tonumber)) 

    # DynamoDB typed list type BS, blob set 
    // (objects | .BS | arrays | map(unmarshal_dynamodb)) 

    # managing others DynamoDB output entries: "Count", "Items", "ScannedCount" and "ConsumedCapcity" 
    // (objects | with_entries(.value |= unmarshal_dynamodb)) 
    // (arrays | map(unmarshal_dynamodb)) 

    # leaves values 
    // . 
    ; 
unmarshal_dynamodb 

Se si salva l'output DynamoDB query in un file, diciamo ddb-query-result.json, è possibile eseguire per ottenere il risultato desiderato:

$> jq -f unmarshal_dynamodb.jq ddb-query-result.json 
+0

Hmm, così è che i nomi chiave dell'oggetto indicano i tipi? Come "S" è per le stringhe, "M" è per le mappe e "N" per i numeri? Puoi davvero fare qualcosa di veramente bello con quello. –

+0

La soluzione 'unmarshal_dynamodb.jq' è brillante e il merito va a te & @JeffMercado. Un difetto nell'usare il '/' che ho cercato di risolvere è che qualsiasi filtro che restituisce false non viene trasformato. Questo è importante per i valori booleani che sono effettivamente impostati su false - mantengono la chiave 'BOOL' o' B'. Ho aggiunto una riga per risolvere parzialmente questo problema, ma non ho ancora trovato un modo per risolverlo completamente senza un secondo passaggio: '// (oggetti | if ha (" BOOL ") o ha (" B ") then [false] else null end) ' Questo aggiunge' false' come array a 1 elemento e deve andare prima della riga "# managing others ...". –

+1

@DaveStern: ho rivisto il metodo qui utilizzato per gestire correttamente i valori di falsy. E ora dovrebbe avere un'implementazione più pulita. –

risposta

6

È possibile decodificare i valori in modo ricorsivo con una funzione ben realizzata.Sembra che i nomi chiave corrispondono a un tipo:

S -> string 
N -> number 
M -> map 

Maniglia ciascuno dei casi si desidera decodificare se possibile, altrimenti filtrare fuori. È possibile utilizzare i vari type filters e lo alternative operator per farlo.

$ cat input.json 
{ 
    "Count": 1, 
    "Items": [ 
    { 
     "Id": { "S": "app1" }, 
     "Parameters": { 
     "M": { 
      "nfs#IP": { "S": "192.17.0.13" }, 
      "maxCount": { "N": "1" }, 
      "nfs#defaultPath": { "S": "/mnt/ebs/" } 
     } 
     } 
    } 
    ], 
    "ScannedCount": 1, 
    "ConsumedCapacity": null 
} 
$ cat ~/.jq 
def decode_ddb: 
    def _sprop($key): select(keys == [$key])[$key];     # single property objects only 
     ((objects | { value: _sprop("S") })       # string (from string) 
    // (objects | { value: _sprop("B") })       # blob (from string) 
    // (objects | { value: _sprop("N") | tonumber })    # number (from string) 
    // (objects | { value: _sprop("BOOL") })      # boolean (from boolean) 
    // (objects | { value: _sprop("M") | map_values(decode_ddb) }) # map (from object) 
    // (objects | { value: _sprop("L") | map(decode_ddb) })   # list (from encoded array) 
    // (objects | { value: _sprop("SS") })       # string set (from string array) 
    // (objects | { value: _sprop("NS") | map(tonumber) })   # number set (from string array) 
    // (objects | { value: _sprop("BS") })       # blob set (from string array) 
    // (objects | { value: map_values(decode_ddb) })    # all other non-conforming objects 
    // (arrays | { value: map(decode_ddb) })      # all other non-conforming arrays 
    // { value: . }).value           # everything else 
    ; 
$ jq 'decode_ddb' input.json 
{ 
    "Count": 1, 
    "Items": [ 
    { 
     "Id": "app1", 
     "Parameters": { 
     "nfs#IP": "192.17.0.13", 
     "maxCount": 1, 
     "nfs#defaultPath": "/mnt/ebs/" 
     } 
    } 
    ], 
    "ScannedCount": 1, 
    "ConsumedCapacity": null 
} 
+0

Grazie all'aiuto di @jeff-mercado. Ho pubblicato una versione estesa della sua funzione 'decode_ddb.jq' come aggiornamento del post originale. – herve

0

Per quanto ne so , non c'è altro output come quello "verboso" che hai postato. Perciò credo, non si può evitare di strumenti intermedi come jq oder sed

Ci sono diverse proposte in questo post per convertire i dati grezzi della dinamo:

Export data from DynamoDB

forse si può adattare uno di questi script in combinazione con jq o sed

+0

con 'jq' è facile, ma non tranquillo, puoi fare qualcosa come:' aws dynamodb query --table-name ConfigCatalog --key-conditions '{"Id": {"AttributeValueList": [{"S ":" app1 "}]," ComparisonOperator ":" EQ "}} '| jq -r '.Items [0] .Parameters.M. "nfs # IP" .S'' il risultato sarà: '172.16.0.178'. Vedi post aggiornato. – herve

0

Ecco un altro approccio. Questo può essere un po 'brutale ma mostra l'idea di base.

def unwanted: ["B","BOOL","M","S","L","BS","SS"]; 
def fixpath(p): [ p[] | select(unwanted[[.]]==[]) ]; 
def fixnum(p;v): 
    if p[-2]=="NS" then [p[:-2]+p[-1:],(v|tonumber)] 
    elif p[-1]=="N" then [p[:-1], (v|tonumber)] 
    else [p,v] end; 

reduce (tostream|select(length==2)) as [$p,$v] (
    {} 
    ; fixnum(fixpath($p);$v) as [$fp,$fv]  
    | setpath($fp;$fv) 
) 

Try it online!

Esempio Run (assumendo filtro filter.jq e dati in data.json)

$ jq -M -f filter.jq data.json 
{ 
    "ConsumedCapacity": null, 
    "Count": 1, 
    "Items": [ 
    { 
     "Id": "app1", 
     "Oldtypes": { 
     "typeBS": [ 
      "VGVybWluYXRvcgo=", 
      "VGVybWluYXRvciAyOiBKdWRnbWVudCBEYXkK", 
      "VGVybWluYXRvciAzOiBSaXNlIG9mIHRoZSBNYWNoaW5lcwo=", 
      "VGVybWluYXRvciA0OiBTYWx2YXRpb24K", 
      "VGVybWluYXRvciA1OiBHZW5lc2lzCg==" 
     ], 
     "typeNS": [ 
      0, 
      1, 
      2, 
      3, 
      4, 
      5 
     ], 
     "typeSS": [ 
      "foo", 
      "bar", 
      "baz" 
     ] 
     }, 
     "Parameters": { 
     "nfs": { 
      "IP": "172.16.0.178", 
      "activated": true, 
      "defaultPath": "/mnt/ebs/", 
      "key": "dGhpcyB0ZXh0IGlzIGJhc2U2NC1lbmNvZGVk" 
     }, 
     "ws": { 
      "number": 5, 
      "values": [ 
      "12253456346346", 
      "23452353463464", 
      "23523453461232", 
      "34645745675675", 
      "46456745757575" 
      ] 
     } 
     } 
    } 
    ], 
    "ScannedCount": 1 
}