Moim celem jest spłaszczenie struktury podobnej do systemu plików (zagnieżdżonych katalogów) z informacjami historycznymi dla poszczególnych plików do pliku csv do dalszego przetwarzania. Tutaj jest to, czego próbowałem do tej pory.

Uproszczone dane wejściowe wyglądają następująco:

{ "dirs": [
    { 
        "name": "documents",
        "files": [
            {
                "name": "foo.bar",
                "history": [
                    { "hash": "123", "timestamp": "..."},
                    { "hash": "234", "timestamp": "..."}
                ]
            }
        ],
        "subDirs": [
            { "name": "tmp", "files": [...], "subDirs": [...]
            }
        ]        
    }
]}

Podstępna część polega na tym, że plik csv powinien zawierać pełne ścieżki katalogów, a nie tylko nazwę katalogu. Żądane wyjście wygląda następująco:

"documents","foo.bar","123","..."
"documents","foo.bar","234","..."
"documents","bar.baz","345","..."
"documents","bar.baz","456","..."
"documents/tmp","deleteme","567","..."
"documents/tmp","deleteme","678","..."

Spłaszczanie większości danych przy użyciu recurse działa przy użyciu tego zapytania:

.dirs[] | recurse(.subDirs[]?) | . as $d | $d.files[]? as $f | $f.history[]? as $h | [$d.name, $f.name, $h.hash, $h.timestamp] | @csv

... ale nie mogę pojąć, jak mogę zachować ścieżkę do katalogu. Wszelkie sugestie będą mile widziane.

1
Buxel 20 marzec 2020, 17:53

2 odpowiedzi

Najlepsza odpowiedź

Myślę, że musisz zdefiniować w tym celu niestandardową funkcję rekurencyjną, jak poniżej; co zakłada, że wszystkie pliki mają niepusty history.

def f(pfix):
    ( [ pfix, .name ] | join("/") ) as $path |
    ( .files[] | .history[] as $hist | [ $path, .name, $hist[] ] ),
    ( .subDirs[] | f($path) );
.dirs[] | f(empty) | @csv
2
oguz ismail 21 marzec 2020, 16:31

Oto podejście, które ani nie używa rekurencji jawnie (*), ani nie opiera się na strukturze rekurencyjnej:

def names($path):
  reduce getpath($path[0:range(0; $path|length)]) as $v ("";
    if $v | type == "object" and has("name") then . + "/" + $v["name"] else . end) ;

paths as $p
| getpath($p) as $v
| select($v | objects | has("history"))
| [names($p), getpath($p + ["name"])]
  + ($v["history"][] | [.hash, .timestamp] )
| @csv

Daje to ścieżki „bezwzględne” (np. „/ Dokumenty”); pominięcie wiodącego „/” może być wykonane dość łatwo.


(*) paths jest zdefiniowane rekurencyjnie, ale w sposób, który wykorzystuje optymalizację wywołań ogonowych (TCO) jq, która jest stosowana tylko do funkcji rekurencyjnych arity-0.

3
peak 20 marzec 2020, 21:19