sql >> データベース >  >> NoSQL >> MongoDB

jqを使用して任意のネストされたJSONをCSVに変換する方法–それを元に戻すことができますか?

    次のtocsv およびfromcsv 関数は、ヘッダーに関する要件(6)に関する1つの複雑さを除いて、述べられた問題の解決策を提供します。基本的に、この要件は、行列転置ステップを追加することにより、ここで提供される関数を使用して満たすことができます。

    転置ステップが追加されているかどうかに関係なく、ここで採用されているアプローチの利点は、JSONキーまたは値に制限がないことです。特に、ピリオド(ドット)、改行、NUL文字が含まれている場合があります。

    この例では、オブジェクトの配列が示されていますが、実際には、有効なJSONドキュメントの任意のストリームをtocsvへの入力として使用できます。; jqの魔法のおかげで、元のストリームはfromcsvによって再作成されます (エンティティごとの平等という意味で)

    もちろん、CSV規格がないため、tocsvで作成されたCSV 機能がすべてのCSVプロセッサで理解されるとは限りません。特に、tocsvに注意してください ここで定義された関数は、JSON文字列またはキー名に埋め込まれた改行を2文字の文字列「\ n」(つまり、リテラルのバックスラッシュの後に文字「n」が続く)にマップします。逆演算は、「ラウンドトリップ」を満たすために逆変換を実行します。要件。

    tailの使用 プレゼンテーションを単純化するだけです。ソリューションを変更して、jqのみにするのは簡単です。)

    CSVは、(a)フィールドが引用符で囲まれ、(b)フィールド内の二重引用符が二重になっている限り、任意の値をフィールドに含めることができるという前提で生成されます。

    「ラウンドトリップ」をサポートする一般的なソリューションは、やや複雑になります。ここに示すソリューションが予想よりも複雑である主な理由は、3番目の列が追加されているためです。これは、整数と整数値の文字列を簡単に区別できるようにするためですが、主にサイズ1とサイズを簡単に区別できるためです。 -jqの--streamによって生成された2つの配列 オプション。言うまでもなく、これらの問題に対処する方法は他にもあります。 jqへの呼び出しの数も減らすことができます。

    このソリューションは、テストケースを伝える際のラウンドトリップ要件をチェックするテストスクリプトとして提示されます。

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

    これがjson | tocsv 、SOが文字通りのNULを許可していないように見えることを除いて、私はそれを\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. mongodb phpドライバーをアンインストールし、別のバージョンをインストールします

    2. MongoDB結果クエリをフラット化することは可能ですか?

    3. SQLでグループの最大値を持つ行を選択する5つの方法

    4. MongoDB.Driver.Buildersグループ化して平均を取得する方法