Postgres JSONb che include array in XML con chiave, valore e valore

Oct 14 2020

Ho una tabella come di seguito:

id  (VARCHAR) | field1 (text) | attributes  (jsonb)     
--------------+---------------+----------------------------------

 123          |   a           |   {"age": "1", "place": "TX"}                 
 456          |   b           |   {"age": "2", "name": "abcdef"}     
 789          |               |       
 098          |   c           |   {"name": ["abc", "def", "ghi"]}     

Vorrei convertirlo in:

 <Company id="123" field="a">
      <CompanyTag tagName="age" tagValue="1"/>
      <CompanyTag tagName="place" tagValue="TX"/>
 </Company>
 <Company id="456" field="b">
      <CompanyTag tagName="age" tagValue="2"/>
      <CompanyTag tagName="name" tagValue="abcdef"/>
 </Company>
 <Company id="789"/>
  <Company id="098" field="c">
      <CompanyTag tagName="name" tagValue="abc"/>
      <CompanyTag tagName="name" tagValue="def"/>
      <CompanyTag tagName="name" tagValue="ghi"/>
 </Company>

Con l'aiuto di @bergi e @Georges Martin in Post è stato in grado di convertire il non array utilizzando la query seguente:

SELECT XMLELEMENT(
  NAME "Company", 
  XMLATTRIBUTES(id AS id, field1 AS field), 
  (SELECT XMLAGG(
    XMLELEMENT(
      NAME "companyTag", 
      XMLATTRIBUTES(
        attr.key AS "tagName", 
        attr.value AS "tagValue"
      )
    )
  ) FROM JSONB_EACH_TEXT(attributes) AS attr)
) FROM comp_emp;

Tuttavia, i valori dell'array vengono visualizzati come di seguito:

 <Company id="098" field="c">
      <CompanyTag tagName="name"tagValue="[&quot;abc&quot;, &quot;def&quot;, &quot;ghi&quot;]"/> 

Non voglio menzionare la chiave ("tagName") in modo specifico nella query poiché potrebbe variare. Supponendo che ciò sia causato da JSONB_EACH_TEXT che estrae i valori più esterni. C'è un'alternativa?

Per favore guidami nella giusta direzione.

Risposte

Bergi Oct 14 2020 at 21:20

Avrai bisogno di un extra per jsonb_array_elements_textestrarre i valori se hai a che fare con un array. Fatto con una giunzione laterale:

SELECT XMLAGG(
  XMLELEMENT(
    NAME "CompanyTag", 
    XMLATTRIBUTES(
      attr.key AS "tagName", 
      values.element AS "tagValue"
    )
  )
) FROM jsonb_each(attributes) AS attr,
LATERAL jsonb_array_elements_text(CASE jsonb_typeof(attr.value)
  WHEN 'array' THEN attr.value
  ELSE jsonb_build_array(attr.value)
END) AS values(element)

( demo online , con query completa)