2017-02-09 3 views
0

Update: Ich habe mit dem Extrahieren der Pfade experimentierte ich wünsche, diese Pfade relativ zum lokalen zu aktualisieren und zu verwenden und zurückgegebenen Objekte (lesen Sie unten) in einem SetPath (Pfade; getPath (Pfade)) Konstruktion. Ich kann jetzt über das $ paths-Array iterieren und die gewünschten Aktualisierungen für das lokale json-Objekt vornehmen.jq versucht, über zwei Sätze von Werten iterieren

Mit der thermostats2.json Datei unten und eine ret.json, die von thermostats2.json unterscheidet sich nur in:

{ "Lage": { "Wohnzimmer": { "Sollwerte": { "Tag":“ 25000 "}}}} #vs {" Tag ":" 23000" }

mein Skript sieht jetzt aus wie:

. as $obj | 

# obtain location keys from $obj as they may have changed locally prior to $retobj being processed 

($obj.location | keys?) as $locs | 

# setpoints are fixed in this code as ["day","night","away"] 

["day","night","away"] as $setpoints | 

[path($obj.location[($locs[])].setpoints[($setpoints[])])] as $paths | 

reduce 
    range(0; $paths|length) as $i 
(.; . | setpath($paths[$i];($retobj[0] | getpath($paths[$i]))) ) | . 

ich nicht die $ obj Variable in dieser Zeit brauchen, aber ich habe nicht das noch aufgeräumt. Bitte kommentieren Sie, wenn Sie Probleme mit diesem Ansatz sehen oder wenn dies wie eine gute Lösung aussieht. Ich werde diese Frage beantworten, wenn die Kommentare anzeigen, dass es sein sollte.

Ich habe ein Json-Objekt, das mehrere Standort enthält jede Objekte, die wiederum mehrere Soll Objekte enthält unter anderem Daten. Dieses json-Objekt wird von einer Remote-Anwendung zur Verfügung gestellt und gibt bei Bedarf Aktualisierungen an die Werte der Sollwertobjekte zurück. Ich möchte das lokale json-Objekt aktualisieren, anstatt es durch das zurückgegebene Objekt zu ersetzen.

Ich will nicht sind das zurückgegebene Objekt Standort Schlüssel zu übernehmen identisch mit denen des lokalen Objekt als lokales Objekt beibehalten worden, während das entfernte Objekt modifiziert wurde. mit den Soll-Tasten, deren Werte Ich interessiere mich für die Aktualisierung

Ich habe herausgefunden, wie die Ortsschlüssel aus der lokalen Datei zu extrahieren und ein Array erstellen. Ich war auch in der Lage, herauszufinden, wie man die aktualisierten Werte vom zurückgegebenen Objekt in ein Array reduziert.

Was ich nicht ist herausgefunden, wie die Standorte iterieren und den Sollwerten zusammen, um die Werte in dem lokalen JSON-Objekt zu aktualisieren.

Ich rufe JQ mit:

# usage : jq --slurpfile retobj ret.json --from-file query.jq thermostats2.json 

query.jq contains: 
# use $obj as the local object to be updated with values returned in $retobj 
# $retobj is not permitted to modify the structure of $obj 

. as $obj | 

# obtain location keys from $obj as they may have changed locally prior to $retobj being processed 

($obj.location | keys?) as $locs | 

# setpoints are fixed in this code as ["day","night","away"] 

["day","night","away"] as $setpoints | 
reduce $retobj[0].location[($locs[])].setpoints[($setpoints[])] as $item 
([]; . + [$item]) 
| . as $vals | 
$vals 

thermostats2.json:

{ "mode":"Home", 
    "location": { 
    "livingroom": { 
    "scale":"Celcius", 
    "current": { 
     "valid":"YES", 
     "reading":"23000", 
     "time":"000000" 
    }, 
    "previous": { 
     "reading":"23000", 
     "time":"000000" 
    }, 
    "setpoints": { 
     "schedule": { 
     "weekday": {"day":"0600", 
       "night":"2100" 
       }, 
     "weekend": {"day":"0630", 
       "night":"2200" 
       } 
     }, 
     "active":"day", 
     "day":"23000", 
     "night":"15556", 
     "away":"12778" 
    } 
    }, 
    "familyroom": { 
    "scale":"Celcius", 
    "current": { 
     "valid":"YES", 
     "reading":"23000", 
     "time":"000000" 
    }, 
    "previous": { 
     "reading":"23000", 
     "time":"000000" 
    }, 
    "setpoints": { 
     "schedule": { 
     "weekday": {"day":"0600", 
       "night":"2100" 
       }, 
     "weekend": {"day":"0630", 
       "night":"2200" 
       } 

     }, 
     "active":"day", 
     "day":"23000", 
     "night":"15556", 
     "away":"12778" 
    } 
    }, 
    "28-000005e2fdef": { 
    "scale":"Celcius", 
    "current": { 
     "valid":"YES", 
     "reading":"23000", 
     "time":"000000" 
    }, 
    "previous": { 
     "reading":"23000", 
     "time":"000000" 
    }, 
    "setpoints": { 
     "schedule": { 
     "weekday": {"day":"0600", 
       "night":"2100" 
       }, 
     "weekend": {"day":"0630", 
       "night":"2200" 
       } 
     }, 
     "active":"day", 
     "day":"23000", 
     "night":"15556", 
     "away":"12778" 
    } 
    } 
    } 
} 

Was kann ich nicht finden, ist jedes Mittel die Werte für die gleichen Objekte in $ obj zu setzen, dh effektiv:

$ obj [0] .location [($ locs [])]. Sollwerte [($ Sollwerte [])] = $ vals

ich unter Ich stelle fest, dass ich als Neuling wahrscheinlich nicht den bevorzugten Ansatz zur Lösung dieser Art von Problemen wähle. Ich bin auch mit Umfassen des Filter Paradigma in einigen der eingebauten Funktionen zu kämpfen, vor allem foreach.

mein Ziel rekapitulieren, mag ich:

die richtigen Objektwert in $ retobj über Ortsschlüssel aus der lokalen obj und der Soll-Taste im Filter definiert abgeleitet erhalten, und die gleichen Pfade in lokalem Objekt gesetzt zu diesen Werten.

+0

1 Wo ist ret.json? 2. Wäre es möglich, das Beispiel auf etwas zu reduzieren, das näher am Minimalen liegt, so dass Sie auch die erwartete Ausgabe leicht anzeigen können? Siehe http://stackoverflow.com/help/mcve – peak

+0

Gegenwärtig ist ret.json genau dasselbe wie thermostats2.json außer {location: {livingroom: {setpoints: {tag: 25000}}}} Ich werde versuchen zu arbeiten auf einer einfacheren Menge von Objekten, wenn ich mit der Suche nach einem Ansatz fertig bin, der path() getpath (Pfade) und setpath (Pfade; Wert) verwendet. Es ist mir gelungen, ein Array von Pfaden zu konstruieren, die zum Aktualisieren und Anwenden eines Elements dieses Arrays sowohl auf das obj als auch auf retobj verwendet werden können. Ich werde meine Frage bearbeiten Ich habe ein bisschen mehr Informationen. – mrh53

Antwort

0

Basierend auf meinem Verständnis der Frage glaube ich, dass die Verwendung von --argfile anstatt --slurpfile die Dinge vereinfachen würde.

Der folgende Filter wird $ retobj anpassen basierend auf dem Inhalt von thermostats2.json:

. as $in 
| reduce ["location", 
      (.location | keys[]), 
      "setpoints", 
      ["day","night","away"][]] as $path 
    ($retobj; 
     setpath($path; ($in | getpath($path)))) 

Invocation: jq --argfile retobj ret.json -f query.jq thermostats2.json

+0

Danke. Abgesehen von der Umkehrung des Ziels, den Inhalt von thermostats2.json basierend auf $ retobj zu ändern, bestätigt Ihre Antwort den Ansatz, den ich letzte Nacht untersucht habe, und beleuchtet zusätzlich eine alternative Notation für den Aufbau von $ path, die ich nur langsam verstanden habe. Ich werde auch überprüfen --argfile vs - Slurpfile, um zu verstehen, wann zu verwenden. Obwohl ich nur für ein paar Tage mit jq gearbeitet habe, bin ich von der Kompaktheit der Ausdrücke beeindruckt. Wow, was für eine Lernkurve! – mrh53

+0

Nur die Dokumentation für --argfile: "Nicht verwenden. Verwenden Sie --slurpfile stattdessen." – mrh53

+0

--argfile gibt es schon länger als --slurpfile und im vorliegenden Fall macht es die Sache leichter in dem Sinne, dass wenn man --slurpfile benutzt, man sich daran erinnern muss, "was" gerade "schlürfte" zu "glätten". – peak

Verwandte Themen