Dans jq, la paire jq map sert à transformer un tableau JSON sans réécrire toute la structure à la main. Je vais montrer comment le filtre map fonctionne, quand il vaut mieux lui préférer select ou map_values, et comment l’appliquer à des données d’API, à des listes imbriquées ou à des objets à normaliser. Dans un contexte backend ou web, c’est souvent le moyen le plus rapide de nettoyer un payload avant de le transmettre plus loin.
Transformer des tableaux JSON sans surprise avec map
-
map(f)applique un filtre à chaque élément d’un tableau et reconstruit un nouveau tableau. - La forme équivalente est
[.[] | f], ce qui aide à comprendre ce que jq exécute réellement. - Si vous travaillez sur un objet,
map_values(f)est souvent plus adapté quemap. -
mapest excellent pour normaliser, projeter ou filtrer des listes issues d’une API. - Un filtre passé à
mappeut supprimer ou dupliquer des éléments selon ses sorties. - Sur des volumes importants, mieux vaut parfois passer à
reduceou au mode streaming.
Ce que fait vraiment map dans jq
jq ne fonctionne pas comme un langage à boucles classique. Il manipule des filtres, et map est simplement un filtre qui prend un tableau en entrée, applique un traitement à chaque élément, puis renvoie un nouveau tableau. La définition pratique à retenir est simple : map(f) équivaut à [.[] | f].
Cette équivalence explique beaucoup de choses. Si le filtre passé à map renvoie une seule valeur par élément, la taille du tableau reste la même. S’il renvoie plusieurs résultats, le tableau s’allonge. S’il renvoie empty ou passe par select, certains éléments disparaissent. En d’autres termes, map ne fait pas qu’“appliquer une fonction” : il reconstruit une sortie à partir de toutes les sorties produites par le filtre interne.
Filtre passé à map
|
Effet sur le résultat | Usage typique |
|---|---|---|
. + 1 |
Une sortie par élément, tableau de même taille | Recalcul simple |
select(.stock > 0) |
Certains éléments sont supprimés | Filtrage de liste |
., . |
Les éléments peuvent être dupliqués | Cas avancé, rare en production |
Je garde ce modèle mental en tête dès que je travaille sur une réponse d’API, parce qu’il évite les faux réflexes. La section suivante montre justement dans quels cas map est le bon choix, et dans quels cas il ne l’est pas.
Quand map est le bon réflexe
J’utilise map quand j’ai une liste homogène et que je veux appliquer la même règle à chaque élément. C’est typiquement le cas pour normaliser des produits, nettoyer des statuts, convertir des nombres, supprimer des champs internes ou reformater un export JSON avant ingestion côté backend.
Ce filtre devient particulièrement utile dans trois situations. D’abord, quand le contrat de données est stable et qu’on veut préparer une sortie propre pour le frontend. Ensuite, quand une API renvoie des champs sous une forme peu pratique, par exemple des nombres stockés en chaînes. Enfin, quand on traite des listes imbriquées, comme des commandes contenant elles-mêmes des lignes de commande ou des catégories contenant des sous-catégories.
| Besoin | Outil le plus direct | Pourquoi |
|---|---|---|
| Transformer chaque élément d’un tableau | map(f) |
Conserve la structure globale |
| Garder seulement certains éléments |
select(...) ou map(select(...))
|
Réduit la liste à ce qui compte |
| Obtenir un total, une somme, une concaténation | reduce |
Produit une seule valeur finale |
| Modifier les valeurs d’un objet | map_values(f) |
Préserve les clés |
En pratique, je pars souvent de cette distinction avant même d’écrire le filtre. C’est plus rapide que de corriger un pipeline trop ambitieux après coup, et cela évite de forcer map là où un autre outil serait plus net.

Exemples pratiques sur des données courantes
Les exemples suivants couvrent les usages que je croise le plus souvent en développement logiciel. Ils sont simples, mais ils montrent bien le vrai intérêt de la fonction : transformer des tableaux sans casser le JSON d’origine.
Incrémenter ou recalculer des valeurs
Le cas le plus basique reste le plus lisible. Si vous avez un tableau de nombres, map permet de les recalculer immédiatement.
echo '[1,2,3]' | jq 'map(. + 1)'
Sortie : [2,3,4]. C’est trivial, mais c’est exactement ce qu’on attend d’un filtre de transformation : même structure, valeurs modifiées.
Nettoyer des statuts ou des libellés techniques
Quand une API renvoie des statuts en majuscules, je les normalise tout de suite pour simplifier les traitements en aval. ascii_downcase est pratique pour des codes techniques, des identifiants ou des statuts anglo-saxons, mais pas pour des textes localisés avec accents.
echo '[{"status":"PENDING"},{"status":"DONE"}]' | jq 'map(.status |= ascii_downcase)'
Sortie : [{"status":"pending"},{"status":"done"}]. Cette étape réduit les incohérences entre services, surtout quand plusieurs équipes alimentent la même donnée.
Recomposer des objets pour une API frontend
J’utilise souvent map pour projeter uniquement les champs utiles et reformater un flux avant de l’envoyer au client. C’est utile quand le backend expose trop de données internes ou quand le frontend n’a besoin que d’un sous-ensemble stable.
echo '[{"id":1,"nom":"Chaise","prix":"49.90","internalId":"x1"}]' | jq 'map({id, nom, prix: (.prix | tonumber)})'
Sortie : [{"id":1,"nom":"Chaise","prix":49.9}]. Ici, on récupère un objet plus propre, avec un prix converti en nombre et un champ interne supprimé implicitement parce qu’il n’est pas réémis.
Lire aussi : Meilleur IDE 2026 - Lequel choisir pour votre projet ?
Traiter des tableaux imbriqués
Quand la structure est en liste de listes, map se combine très bien avec lui-même. C’est simple, lisible, et souvent plus clair qu’un filtre trop compact.
echo '[[1,2],[3,4]]' | jq 'map(map(. + 1))'
Sortie : [[2,3],[4,5]]. Pour des données plus réalistes, la même logique marche sur des commandes et leurs lignes, des sections et leurs éléments, ou des groupes et leurs membres.
À ce stade, on voit bien que map ne sert pas seulement à “faire une opération sur des nombres”. Il sert surtout à exprimer une règle uniforme sur une collection structurée, et c’est précisément ce qu’attend souvent un pipeline backend.
Sur les objets, map_values est souvent plus juste
Le point de friction le plus courant vient des objets. map travaille naturellement sur les tableaux, alors que map_values est conçu pour transformer les valeurs d’un objet sans toucher à ses clés. Si vous passez d’un tableau à un objet, changer de fonction est généralement le bon réflexe.
echo '{"a":1,"b":2,"c":3}' | jq 'map_values(. + 1)'
Sortie : {"a":2,"b":3,"c":4}. Ici, les clés restent intactes, ce qui est exactement ce qu’on veut la plupart du temps lorsqu’on applique un ajustement global à un dictionnaire JSON.
Si vous devez transformer les clés elles-mêmes, je préfère passer par to_entries, map(...) puis from_entries, ou utiliser with_entries quand la logique reste simple. C’est plus explicite qu’un bricolage autour de map, et cela évite les filtres difficiles à relire six mois plus tard.
La règle pratique est donc assez nette : tableau => map, objet => map_values ou une conversion d’entrées. Cette distinction suffit déjà à éliminer une bonne partie des confusions en revue de code.
Les pièges qui reviennent le plus souvent
Le premier piège, c’est d’attendre de map qu’il “filtre” à lui seul. En réalité, il applique le filtre fourni. Si ce filtre renvoie des booléens, vous obtenez des booléens. Si vous voulez garder seulement certains éléments, il faut utiliser select dans le filtre interne.
echo '[{"enabled":true},{"enabled":false}]' | jq 'map(.enabled)'
Sortie : [true,false]. Ce n’est pas un filtrage, c’est une projection. Le filtrage correct ressemble plutôt à ceci :
echo '[{"enabled":true},{"enabled":false}]' | jq 'map(select(.enabled))'
Sortie : [{"enabled":true}]. La différence paraît minime, mais elle change complètement l’intention du pipeline.
Le deuxième piège, c’est la taille des sorties. Si le filtre interne peut émettre plusieurs valeurs ou aucune, la longueur finale du tableau peut changer. C’est utile, mais il faut le prévoir. En code de production, j’évite les filtres “créatifs” quand la forme du JSON doit rester prévisible pour un autre service.
Le troisième piège touche à la mémoire. map reconstruit un tableau complet en sortie, donc il est parfait pour des réponses JSON déjà matérialisées, mais moins adapté à des volumes massifs ou à des flux continus. Dans ce cas, il vaut mieux envisager un mode plus streaming ou une agrégation avec reduce.
Enfin, je vois souvent des filtres trop longs écrits d’un seul bloc. Dès que la logique dépasse deux ou trois opérations, je préfère la découper avec def. Le résultat est plus lisible, plus testable et plus simple à faire évoluer.
Quand passer à autre chose pour rester lisible et rapide
La bonne règle de décision est presque toujours la même. Si vous devez transformer chaque élément d’un tableau, map est le bon outil. Si vous devez supprimer des éléments selon une condition, associez-le à select ou utilisez select directement. Si vous devez produire un total, un compteur ou une concaténation, passez à reduce. Et si votre structure est un objet, ne forcez pas map là où map_values fera le travail sans détour.
Dans un projet backend ou un script d’automatisation, je conseille aussi de tester le filtre sur un petit échantillon représentatif avant de l’appliquer à un dump entier. Cette étape prend peu de temps, mais elle révèle immédiatement les problèmes de forme, les champs manquants et les écarts entre ce qu’on croit transformer et ce que le pipeline produit réellement.
Au fond, le meilleur usage de map est celui qui reste évident à relire : une entrée de tableau, une règle par élément, une sortie de même nature. Dès que la logique n’entre plus dans ce cadre, je change d’outil plutôt que de tordre le filtre, parce qu’en jq, la lisibilité est souvent la vraie économie de temps.