sql >> Databasteknik >  >> NoSQL >> MongoDB

Hur konverterar man godtyckligt kapslad JSON till CSV med jq – så att du kan konvertera tillbaka det?

Följande tocsv och fromcsv funktioner ger en lösning på det angivna problemet förutom en komplikation angående krav (6) angående rubrikerna. I huvudsak kan detta krav uppfyllas med de funktioner som ges här genom att lägga till ett matristransponeringssteg.

Oavsett om ett transponeringssteg läggs till eller inte, är fördelen med tillvägagångssättet här att det inte finns några begränsningar för JSON-nycklarna eller -värdena. I synnerhet kan de innehålla punkter (punkter), rader och/eller NUL-tecken.

I exemplet anges en array av objekt, men i själva verket kan vilken ström av giltiga JSON-dokument som helst användas som indata till tocsv; tack vare jqs magi kommer den ursprungliga strömmen att återskapas av fromcsv (i betydelsen enhet för enhet jämlikhet).

Naturligtvis, eftersom det inte finns någon CSV-standard, produceras CSV:en av tocsv funktionen kanske inte förstås av alla CSV-processorer. Observera i synnerhet att tocsv funktion som definieras här mappas inbäddade nyrader i JSON-strängar eller nyckelnamn till tvåteckensträngen "\n" (d.v.s. ett bokstavligt snedstreck följt av bokstaven "n"); den inversa operationen utför den omvända översättningen för att möta "rundturen" krav.

(Användningen av tail är bara för att förenkla presentationen; det skulle vara bra att modifiera lösningen för att göra den till en endast-jq.)

CSV:n genereras under antagandet att vilket värde som helst kan inkluderas i ett fält så länge som (a) fältet är citerat och (b) dubbla citattecken i fältet dubbleras.

Varje generisk lösning som stöder "tur- och returresor" kommer att bli något komplicerad. Den främsta anledningen till att lösningen som presenteras här är mer komplex än man kan förvänta sig beror på att en tredje kolumn har lagts till, dels för att göra det lätt att skilja mellan heltal och heltalsvärdade strängar, men främst för att det gör det enkelt att skilja mellan storlek-1 och storlek -2 arrayer producerade av jqs --stream alternativ. Det behöver inte sägas att det finns andra sätt att hantera dessa frågor på; antalet samtal till jq kan också minskas.

Lösningen presenteras som ett testskript som kontrollerar kravet på tur och retur på ett talande testfall:

#!/bin/bash

function json {
    cat<<EOF
[
  {
    "a": 1,
    "b": [
      1,
      2,
      "1"
    ],
    "c": "d\",ef",
    "embed\"ed": "quote",
    "null": null,
    "string": "null",
    "control characters": "a\u0000c",
    "newline": "a\nb"
  },
  {
    "x": 1
  }
]
EOF
}

function tocsv {
 jq -ncr --stream '
   (["path", "value", "stringp"],
    (inputs | . + [.[1]|type=="string"]))
   | map( tostring|gsub("\"";"\"\"") | gsub("\n"; "\\n"))
   | "\"\(.[0])\",\"\(.[1])\",\(.[2])" 
'
}

function fromcsv { 
    tail -n +2 | # first duplicate backslashes and deduplicate double-quotes
    jq -rR '"[\(gsub("\\\\";"\\\\") | gsub("\"\"";"\\\"") ) ]"' |
    jq -c '.[2] as $s 
           | .[0] |= fromjson 
           | .[1] |= if $s then . else fromjson end 
           | if $s == null then [.[0]] else .[:-1] end
             # handle newlines
           | map(if type == "string" then gsub("\\\\n";"\n") else . end)' |
    jq -n 'fromstream(inputs)'
}    

# Check the roundtrip:
json | tocsv | fromcsv | jq -s '.[0] == .[1]' - <(json)

Här är CSV:en som skulle produceras av json | tocsv , förutom att SO verkar inte tillåta bokstavliga NUL, så jag har ersatt det med \0 :

"path","value",stringp
"[0,""a""]","1",false
"[0,""b"",0]","1",false
"[0,""b"",1]","2",false
"[0,""b"",2]","1",true
"[0,""b"",2]","false",null
"[0,""c""]","d"",ef",true
"[0,""embed\""ed""]","quote",true
"[0,""null""]","null",false
"[0,""string""]","null",true
"[0,""control characters""]","a\0c",true
"[0,""newline""]","a\nb",true
"[0,""newline""]","false",null
"[1,""x""]","1",false
"[1,""x""]","false",null
"[1]","false",null


  1. Index i MongoDB

  2. Hur använder man $arrayElemAt och tar bort fält från det elementet i MongoDB $projection?

  3. Loggning med winston-mongodb och express-winston

  4. Gruppera distinkta värden och antal för varje egenskap i en fråga