sql >> Databáze >  >> NoSQL >> MongoDB

Jak převést libovolný vnořený JSON na CSV s jq – abyste jej mohli převést zpět?

Následující tocsv a fromcsv funkce poskytují řešení uvedeného problému s výjimkou jedné komplikace týkající se požadavku (6) týkajícího se záhlaví. Tento požadavek lze v podstatě splnit pomocí zde uvedených funkcí přidáním kroku transpozice matice.

Bez ohledu na to, zda je přidán krok transpozice, výhodou tohoto přístupu je, že neexistují žádná omezení pro klíče nebo hodnoty JSON. Zejména mohou obsahovat tečky (tečky), nové řádky a/nebo znaky NUL.

V příkladu je uvedeno pole objektů, ale ve skutečnosti lze jako vstup do tocsv použít jakýkoli proud platných dokumentů JSON; díky kouzlu jq bude původní stream znovu vytvořen pomocí fromcsv (ve smyslu rovnosti entit po entitě).

Vzhledem k tomu, že neexistuje žádný standard CSV, je samozřejmě CSV vytvářený souborem tocsv funkce nemusí být srozumitelná všem procesorům CSV. Zejména mějte na paměti, že tocsv zde definovaná funkce mapuje vložené nové řádky v řetězcích JSON nebo názvech klíčů na dvouznakový řetězec „\n“ (tj. doslovné zpětné lomítko následované písmenem „n“); inverzní operace provede inverzní překlad, aby splnila „zpáteční cestu“ požadavek.

(Použití tail slouží pouze ke zjednodušení prezentace; bylo by triviální upravit řešení tak, aby bylo pouze jq.)

CSV je generován za předpokladu, že do pole může být zahrnuta jakákoli hodnota, pokud (a) pole je uvozováno a (b) dvojité uvozovky v poli jsou zdvojené.

Jakékoli generické řešení, které podporuje „okružní cesty“, musí být poněkud komplikované. Hlavním důvodem, proč je zde prezentované řešení složitější, než by se dalo očekávat, je ten, že byl přidán třetí sloupec, částečně proto, aby bylo snadné rozlišovat mezi celými čísly a řetězci s celočíselnou hodnotou, ale hlavně proto, že usnadňuje rozlišení mezi velikostí-1 a velikostí. -2 pole vytvořená jq--stream volba. Netřeba dodávat, že existují i ​​jiné způsoby, jak tyto problémy řešit; počet volání jq by se také mohl snížit.

Řešení je prezentováno jako testovací skript, který kontroluje požadavek na zpáteční cestu na výmluvném testovacím případu:

#!/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)

Zde je soubor CSV, který by vytvořil json | tocsv , kromě toho, že SO zřejmě nepovoluje doslovné NUL, takže jsem to nahradil \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. Top 10 funkcí Big Data Hadoop

  2. Aplikace Heroku spadne po aktualizaci MongoDB na 3.0

  3. Potřebuji poradit s návrhem databáze v mongodb s mongoose

  4. Jak získám data z Mongodb