2 votes

Comment utiliser jq pour insérer des noms de champs dynamiques de manière récursive pour tous les objets d'un tableau ?

Je suis nouveau dans l'utilisation de jq, et j'espère convertir le JSON ci-dessous de sorte que, pour chaque objet du tableau des enregistrements, l'objet "Account" soit supprimé et remplacé par un champ "AccountID" dont la valeur est Account.Id. En supposant que je ne sache pas quel est le nom du champ (par exemple Account) avant l'exécution, il doit être inclus dynamiquement comme argument de --arg.

Contacts.json :

{
    "records": [
        {
            "attributes": {
                "type": "Contact",
                "referenceId": "ContactRef1"
            },
            "Account": {
                "attributes": {
                    "type": "Account",
                    "url": "/services/data/v51.0/sobjects/Account/asdf"
                },
                "Id": "asdf"
            }
    },
 {
            "attributes": {
                "type": "Contact",
                "referenceId": "ContactRef2"
            },
            "Account": {
                "attributes": {
                    "type": "Account",
                    "url": "/services/data/v51.0/sobjects/Account/qwer"
                },
                "Id": "qwer"
            }
    }
    ]

}

à

{
    "records": [
          {
            "attributes": {
                "type": "Contact",
                "referenceId": "ContactRef1"
            },
            "AccountID": "asdf"
            }
    },{
            "attributes": {
                "type": "Contact",
                "referenceId": "ContactRef2"
            },
            "AccountID": "qwer"
            }
    }
    ]

}

L'exemple ci-dessus est un peu artificiel parce qu'en réalité, je dois être capable de nommer dynamiquement le champ ID pour pouvoir porter la nouvelle structure JSON dans le système de destination. Pour mon cas d'utilisation, il n'est pas toujours possible d'ajouter "ID" au nom du champ ( ex. Account .. ID ), donc j'ai passé les noms des champs à --arg .

C'est ce que j'ai fait de mieux, mais ce n'est pas tout à fait ça et je pense qu'il y a une meilleure façon de faire.

jq -c --arg field "Account" --arg field_name_id "AccountID" '.  |= .  + if .records?[]?[$field] != null then   { "\($field_name_id)" : .records[][$field].Id }  else empty end | if .records?[]?[$field] != null then del(.records[][$field]) else empty end'  Contacts.json

J'ai lutté avec cela pendant un certain temps, mais c'est tout ce que j'ai pu faire sans rencontrer des tonnes d'erreurs de syntaxe. J'apprécierais vraiment toute aide pour ajouter un champ AccountID sur chaque objet dans le tableau des enregistrements.

Voici le script bash script où jq est exécuté (les parties pertinentes sont celles où FIELD(S) est utilisé).

#! /bin/bash
# This script takes a of soql file as first and only argument
# The main purpose is to tweak the json results from an sfdx:data:tree:export so the json is compatible with sfdx:data:tree:import
# This is needed because sfdx export & import are inadequate to use whne  relationships more than 2 levels deep in the export query.

# grab all unique object names within the soql file for any objects where the ID field is being SELECTed ( eg.  "Account Iteration__r Profile UserRole" )
FIELDS=`grep -oe '\([A-Za-z_]\+\)\.[iI][dD]'  $1 | cut -f 1 -d . - | sort -u`

#find all json files in file and rewrite the relationship FIELDS blocks into someting sfdx can import
for FIELD in $FIELDS;

do 

if [[ $FIELD =~ __r ]] 
then
 FIELD_NAME_ID=`sed 's/__r/__c/' <<< $FIELD`
else
FIELD_NAME_ID="${FIELD}ID" 
fi

JSON_FILES=`ls *.json`
#Loop all json files in direcotry
for DATA_FILE in $JSON_FILES
do

#replace any email addresses left in custom data( just in case ) 
#using gsed becuse Mac lacks -i flag for in-place substitution
gsed -i 's/[^@ "]*@[^@]*\.[^@ ,"]*/fake@test.com/g' $DATA_FILE

# make temporary file to hold the rewritten json
TEMP_FILE="temp-${DATA_FILE}.bk"
echo $DATA_FILE $FIELD $FIELD_NAME_ID 

#For custom relationship jttrs. change __r to __c to get the name of Id field, otherwise just add "ID".
jq -c --arg field $FIELD --arg field_name_id $FIELD_NAME_ID '.  |= .  + if .records?[]?[$field] != null then   { "\($field_name_id)" : .records[][$field].Id }  else empty end | if .records?[]?[$field] != null then del(.records[][$field]) else empty end'  $DATA_FILE 1>  ./$TEMP_FILE  2> modify-json.errors

# if TEMP_FILE is not empty, then jq revised it, so replace contents the original JSON DATA_FILE 
if [[ -s ./$TEMP_FILE ]]
then
#JSON format spacing/line-breaks 
jq '.' $TEMP_FILE > $DATA_FILE
fi

rm $TEMP_FILE

done

done

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X