JQ | Probleem met sub data van JSON

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

  • Yagermeister
  • Registratie: December 2001
  • Laatst online: 15:12

Yagermeister

Bedrijfsprutser on call

Topicstarter
Mijn vraag

Wij maken sinds kort gebruik van Picqer en daarmee willen wij onder andere alle relevante data kunnen downloaden om dit verder te processen.

Ik heb onderstaande JSON (maar een paar producten). Hiervan wil ik diverse data uit plukken omdat ik deze nodig heb.

JSON:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
{
  "success": true,
  "data": [
    {
      "idproduct": 10305656,
      "idvatgroup": 9520,
      "idsupplier": 42582,
      "productcode": "00000020",
      "name": "Tefal YV9601 actifry heteluchtfriteuse",
      "price": 200.58,
      ...
      "stock": [
        {
          "idwarehouse": 4862,
          ...
          "freestock": 0
        },
        {
          "idwarehouse": 4863,
          ...
          "freestock": 0
        },
        {
          "idwarehouse": 4861,
          ...
          "freestock": 0
        },
        {
          "idwarehouse": 4865,
          ...
          "freestock": 0
        }
      ],
      ...
    },
    {
      "idproduct": 10379509,
      "idvatgroup": 9520,
      "idsupplier": 42581,
      "productcode": "00000039",
      "name": "Sony MDR-XB50AP EXTRA BASS In-Ear Headphones Zwart",
      "price": 81.12,
      ...
      "stock": [],
      ...
    }
    ]
    
}


De velden die ik wil hebben zijn als volgt:

idproduct, idvatgroup, idsupplier, productcode, name, price, stock per magazijn (alleen freestock)


Relevante software en hardware die ik gebruik

Omdat dit JSON is ben ik vooral aan het proberen met JQ. Nu heb ik onderstaande opdrachtregel die grotendeels werkt echter lukt het me niet om de (free)stock per magazijn achter elkaar te krijgen. Ik wil dit namelijk graag in een CSV hebben staan

Wat ik al gevonden of geprobeerd heb

Op https://jqplay.org kun je alles proberen wat het een stuk makkelijker maakt. Hiermee heb ik onderstaande opdrachtregel (linux debian) al mee gegenereerd echter dat laatste stukje van de stock kom ik niet mee weg.


code:
1
jq --compact-output '.data[] | { idproduct, idvatgroup, idsupplier, productcode, name, price, stock } | [.idproduct, .idvatgroup, .idsupplier, .productcode, .name, .price, .stock]'


Omgezet naar mijn bash script kom ik met het volgende (stock is weggelaten omdat die niet de juiste weergave heeft):
code:
1
cat json1.json | jq --compact-output '.data[] | { idproduct, idvatgroup, idsupplier, productcode, name, price } | [.idproduct, .idvatgroup, .idsupplier, .productcode, .name, .price]'| sed 's/"//g;s/,/;/g;s/\[//g;s/\]//g'


Output:
code:
1
2
3
10305656;9520;42582;00000020;Tefal YV9601 actifry heteluchtfriteuse;200.58
10379509;9520;42581;00000039;Sony MDR-XB50AP EXTRA BASS In-Ear Headphones Zwart;81.12
10304234;9520;null;00000041;Philips AVENT DECT-babyfoon SCD580/00;0


Wat ik dus nodig is dus bovenstaande met de toevoeging van het warehouseid en freestock.

[ Voor 43% gewijzigd door RobIII op 28-08-2019 16:43 . Reden: JSON drastisch ingekort met enkel relevante json. ]

-Te huur

Beste antwoord (via Yagermeister op 29-08-2019 11:14)


  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 20:09
Gewoon even goed kijken wat de verschillende filters/operators doen. (Ik had wel van jq gehoord, maar dit is ook de eerste keer dat ik er echt iets mee doe.)

Het middelste deel van je expressie (tussen de pipe-karakters) is sowieso overbodig. In het laatste deel maak je een array waarbij je alleen de voor jou relevante keys selecteert, dus je hoeft niet daarvoor eerst al de niet relevante keys eruit te filteren.

Dan de stock: je pakt nu alle elementen van de array en filtert daar de idwarehouse uit en dan pak je nogmaals alle elementen en filtert met freestock. Wat je wilt is slechts één keer alle elementen uit de array pakken en dan per element die twee relevante keys selecteren. Dat is dus hetzelfde als een niveau hoger met de data array.

jq heeft ook nog ingebouwde csv-conversie (op jqplay):
Bash:
1
jq --raw-output '.data[] | [.idproduct, .idvatgroup, .idsupplier, .productcode, .name, .price, (.stock[] | .idwarehouse, .freestock)] | @csv'


Edit: ik gooi ook nog even Wikipedia: Useless use of cat erin.

[ Voor 6% gewijzigd door Raynman op 29-08-2019 11:12 ]

Alle reacties


Acties:
  • +1 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Net zoals idproduct onder data zit, zit de freestock onder elke stock. Zijn dit altijd een vast aantal van 4 elementen? Nee dus, ik zie, na flink opschonen van je JSON* tot er alleen maar relevante zaken in staan (zie de edit van je post), ook producten met 0 elementen in de stock entry. Dus een variabel aantal stock elementen.

Ik ken JQ niet (en bash is al helemaal niet mijn sterkste punt) maar ik zie je in ieder geval nergens dat "niveau" in duiken in de "boom". Je zou iets verwachten als stock[].freestock of stock[0].freestock of iets dergelijks.

* Wil je voortaan zélf zorgen dat je een beetje een behapbaar stukje relevante(!) code post? ;)

Edit: Dit lijkt te werken (ook op je volledige JSON):
code:
1
.data[] | { idproduct, idvatgroup, idsupplier, productcode, name, price, stock } | [.idproduct, .idvatgroup, .idsupplier, .productcode, .name, .price, .stock[].freestock]

Mag je warehouseid zelf doen ;)

[ Voor 78% gewijzigd door RobIII op 28-08-2019 16:41 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Yagermeister
  • Registratie: December 2001
  • Laatst online: 15:12

Yagermeister

Bedrijfsprutser on call

Topicstarter
Sorry,

Ik zag net idd dat ik per ongeluk niet de volle JSON gepost heb }:O

In ieder geval bedankt voor je toevoeging echter komt nu weer het maartje om de bocht:

Ik heb nu de warehouseid erbij met onderstaande regel:
code:
1
.data[] | { idproduct, idvatgroup, idsupplier, productcode, name, price, stock } | [.idproduct, .idvatgroup, .idsupplier, .productcode, .name, .price, .stock[].idwarehouse, .stock[].freestock]


Wat nu echter wel gebeurt is dat hij eerst de id's zet en dan pas de stock. Is het mogelijk om dit als volgt te krijgen: ID, Stock, ID2, Stock2, etc?

edit:

even een toevoeging waarom ik bovenstaande vraag. De volgorde van de warehouseid's kan per product verschillen wat het natuurlijk lastig maakt om daar een touw aan vast te knoppen als deze niet erbij staat.

[ Voor 16% gewijzigd door Yagermeister op 29-08-2019 09:51 ]

-Te huur


Acties:
  • Beste antwoord
  • +1 Henk 'm!

  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 20:09
Gewoon even goed kijken wat de verschillende filters/operators doen. (Ik had wel van jq gehoord, maar dit is ook de eerste keer dat ik er echt iets mee doe.)

Het middelste deel van je expressie (tussen de pipe-karakters) is sowieso overbodig. In het laatste deel maak je een array waarbij je alleen de voor jou relevante keys selecteert, dus je hoeft niet daarvoor eerst al de niet relevante keys eruit te filteren.

Dan de stock: je pakt nu alle elementen van de array en filtert daar de idwarehouse uit en dan pak je nogmaals alle elementen en filtert met freestock. Wat je wilt is slechts één keer alle elementen uit de array pakken en dan per element die twee relevante keys selecteren. Dat is dus hetzelfde als een niveau hoger met de data array.

jq heeft ook nog ingebouwde csv-conversie (op jqplay):
Bash:
1
jq --raw-output '.data[] | [.idproduct, .idvatgroup, .idsupplier, .productcode, .name, .price, (.stock[] | .idwarehouse, .freestock)] | @csv'


Edit: ik gooi ook nog even Wikipedia: Useless use of cat erin.

[ Voor 6% gewijzigd door Raynman op 29-08-2019 11:12 ]


  • Yagermeister
  • Registratie: December 2001
  • Laatst online: 15:12

Yagermeister

Bedrijfsprutser on call

Topicstarter
Raynman schreef op donderdag 29 augustus 2019 @ 11:09:
Gewoon even goed kijken wat de verschillende filters/operators doen. (Ik had wel van jq gehoord, maar dit is ook de eerste keer dat ik er echt iets mee doe.)

Het middelste deel van je expressie (tussen de pipe-karakters) is sowieso overbodig. In het laatste deel maak je een array waarbij je alleen de voor jou relevante keys selecteert, dus je hoeft niet daarvoor eerst al de niet relevante keys eruit te filteren.

Dan de stock: je pakt nu alle elementen van de array en filtert daar de idwarehouse uit en dan pak je nogmaals alle elementen en filtert met freestock. Wat je wilt is alle elementen uit de array pakken en dan per element die twee relevante keys selecteren. Dat is dus hetzelfde als een niveau hoger met de data array.

jq heeft ook nog ingebouwde csv-conversie (op jqplay):
Bash:
1
jq --raw-output '.data[] | [.idproduct, .idvatgroup, .idsupplier, .productcode, .name, .price, (.stock[] | .idwarehouse, .freestock)] | @csv'


Edit: ik gooi ook nog even Wikipedia: Useless use of cat erin.
toon volledige bericht
Dank en hulde voor deze oplossing. Ik was net mijn eigen gevonden oplossing aan het intikken om ook te posten. Dit is dan wel niet met JQ maar het geeft me ook de waardes die ik nodig heb.

Onderstaand mijn gevonden oplossing in ieder geval:

Ik heb een script gevonden op https://gist.github.com/bzerangue/4982951 welke mij de json omzet naar een XML.

Deze XML heb ik daarna via onderstaande code uitgevoerd om dan de kolomen ineens op de goede volgorde te zetten zodat ik niet perse de warehouseid nodig heb omdat de kolomvolgorde daarvoor ook goed is.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
php json2xml.php > test.xml

xmlstarlet sel -T -t -m /searchresults/data -v "concat(idproduct,';', \
        idvatgroup,';', \
        idsupplier,';', \
        productcode,';', \
        name,';', \
        price,';', \
        fixedstockprice,';', \
        productcode_supplier,';', \
        deliverytime,';', \
        barcode,';', \
        stock[idwarehouse="4861"]/freestock,';', \
        stock[idwarehouse="4865"]/freestock,';', \
        stock[idwarehouse="4862"]/freestock,';', \
        stock[idwarehouse="4863"]/freestock
)" -n test.xml >> test.csv


Hiermee krijg ik ook de benodigde csv met alle relevante data die ik wil hebben.

Nogmaals bedankt voor het meedenken in ieder geval.

-Te huur