L’auteur a sélectionné la Société des ingénieures pour recevoir une donation dans le cadre du programme Write for DOnations.
Introduction
A CSV is a plain text file format for storing tabular data. The CSV file uses a comma delimiter to separate values in table cells, and a new line delineates where rows begin and end. Most spreadsheet programs and databases can export and import CSV files. Because CSV is a plain-text file, any programming language can parse and write to a CSV file. Node.js has many modules that can work with CSV files, such as node-csv
, fast-csv
, and papaparse
.
Dans ce tutoriel, vous utiliserez le module node-csv
pour lire un fichier CSV à l’aide des flux Node.js, ce qui vous permettra de lire de grands ensembles de données sans consommer beaucoup de mémoire. Vous allez modifier le programme pour déplacer les données analysées à partir du fichier CSV dans une base de données SQLite. Vous récupérerez également des données de la base de données, les analyserez avec node-csv
, et utiliserez les flux Node.js pour les écrire dans un fichier CSV par tranches.
Déployez vos applications Node depuis GitHub en utilisant la plateforme d’application DigitalOcean. Laissez DigitalOcean se concentrer sur le dimensionnement de votre application.
Prérequis
Pour suivre ce tutoriel, vous aurez besoin de :
-
Node.js installé sur votre environnement local ou serveur. Suivez Comment installer Node.js et créer un environnement de développement local pour installer Node.js.
-
SQLite installé sur votre environnement local ou serveur, que vous pouvez installer en suivant l’étape 1 de Comment installer et utiliser SQLite sur Ubuntu 20.04. La connaissance de l’utilisation de SQLite est utile et peut être apprise dans les étapes 2 à 7 du guide d’installation.
-
Familiarité avec l’écriture d’un programme Node.js. Voir Comment écrire et exécuter votre premier programme en Node.js.
-
Familiarité avec les flux Node.js. Voir Comment travailler avec des fichiers en utilisant des flux en Node.js.
Étape 1 — Configuration du répertoire du projet
Dans cette section, vous allez créer le répertoire du projet et télécharger des paquets pour votre application. Vous téléchargerez également un ensemble de données CSV auprès de Stats NZ, qui contient des données sur la migration internationale en Nouvelle-Zélande.
Pour commencer, créez un répertoire appelé csv_demo
et naviguez dans le répertoire :
Ensuite, initialisez le répertoire en tant que projet npm en utilisant la commande npm init
:
L’option -y
notifie npm init
pour dire « oui » à toutes les invites. Cette commande crée un package.json
avec des valeurs par défaut que vous pouvez modifier à tout moment.
Avec le répertoire initialisé en tant que projet npm, vous pouvez maintenant installer les dépendances nécessaires : node-csv
et node-sqlite3
.
Entrez la commande suivante pour installer node-csv
:
Le module node-csv
est une collection de modules qui vous permet de parser et d’écrire des données dans un fichier CSV. La commande installe les quatre modules qui font partie du package node-csv
: csv-generate
, csv-parse
, csv-stringify
et stream-transform
. Vous utiliserez le module csv-parse
pour parser un fichier CSV et le module csv-stringify
pour écrire des données dans un fichier CSV.
Ensuite, installez le module node-sqlite3
:
Le module node-sqlite3
permet à votre application d’interagir avec la base de données SQLite.
Après avoir installé les packages dans votre projet, téléchargez le fichier CSV de migration en Nouvelle-Zélande avec la commande wget
:
Le fichier CSV que vous avez téléchargé a un nom long. Pour faciliter son utilisation, renommez le nom de fichier en un nom plus court à l’aide de la commande mv
:
Le nouveau nom de fichier CSV, migration_data.csv
, est plus court et plus facile à utiliser.
À l’aide de nano
, ou de votre éditeur de texte favori, ouvrez le fichier :
Une fois ouvert, vous verrez un contenu similaire à ceci :
year_month,month_of_release,passenger_type,direction,sex,age,estimate,standard_error,status
2001-01,2020-09,Long-term migrant,Arrivals,Female,0-4 years,344,0,Final
2001-01,2020-09,Long-term migrant,Arrivals,Male,0-4 years,341,0,Final
...
La première ligne contient les noms des colonnes, et toutes les lignes suivantes contiennent les données correspondant à chaque colonne. Une virgule sépare chaque donnée. Ce caractère est appelé délimiteur car il délimite les champs. Vous n’êtes pas limité à utiliser des virgules. D’autres délimiteurs populaires incluent les deux-points (:
), les points-virgules (;
) et les tabulations (\t
). Vous devez savoir quel délimiteur est utilisé dans le fichier car la plupart des modules en ont besoin pour parser les fichiers.
Après avoir examiné le fichier et identifié le délimiteur, quittez votre fichier migration_data.csv
en utilisant CTRL+X
.
Vous avez maintenant installé les dépendances nécessaires pour votre projet. Dans la section suivante, vous lirez un fichier CSV.
Étape 2 — Lecture des fichiers CSV
Dans cette section, vous utiliserez node-csv
pour lire un fichier CSV et enregistrer son contenu dans la console. Vous utiliserez la méthode createReadStream()
du module fs
pour lire les données du fichier CSV et créer un flux lisible. Ensuite, vous redirigerez le flux vers un autre flux initialisé avec le module csv-parse
pour analyser les morceaux de données. Une fois que les morceaux de données ont été analysés, vous pouvez les enregistrer dans la console.
Créez et ouvrez un fichier readCSV.js
dans votre éditeur préféré:
Dans votre fichier readCSV.js
, importez les modules fs
et csv-parse
en ajoutant les lignes suivantes:
Dans la première ligne, vous définissez la variable fs
et lui attribuez l’objet fs
que la méthode require()
de Node.js renvoie lorsqu’elle importe le module.
Dans la deuxième ligne, vous extrayez la méthode parse
de l’objet retourné par la méthode require()
dans la variable parse
en utilisant la syntaxe de déstructuration.
Ajoutez les lignes suivantes pour lire le fichier CSV :
La méthode createReadStream()
du module fs
accepte un argument du nom de fichier que vous souhaitez lire, qui est migration_data.csv
ici. Ensuite, elle crée un flux lisible, qui prend un fichier volumineux et le divise en petits morceaux. Un flux lisible vous permet de lire uniquement les données à partir de celui-ci et de ne pas écrire dedans.
Après avoir créé le flux lisible, la méthode pipe()
de Node transfère les morceaux de données du flux lisible vers un autre flux. Le deuxième flux est créé lorsque la méthode parse()
du module csv-parse
est invoquée à l’intérieur de la méthode pipe()
. Le module csv-parse
implémente un flux de transformation (un flux lisible et inscriptible), prenant un morceau de données et le transformant en une autre forme. Par exemple, lorsqu’il reçoit un morceau comme 2001-01,2020-09,Migration de long terme,Arrivées,Femelle,0-4 ans,344
, la méthode parse()
le transformera en un tableau.
La méthode parse()
prend un objet qui accepte des propriétés. L’objet configure ensuite et fournit plus d’informations sur les données que la méthode analysera. L’objet prend les propriétés suivantes:
-
delimiter
définit le caractère qui sépare chaque champ dans la ligne. La valeur,
indique au parseur que les virgules délimitent les champs. -
from_line
définit la ligne où le parseur doit commencer à analyser les lignes. Avec la valeur2
, le parseur sautera la ligne 1 et commencera à la ligne 2. Comme vous allez insérer les données dans la base de données plus tard, cette propriété vous aide à éviter d’insérer les noms de colonnes dans la première ligne de la base de données.
Ensuite, vous attachez un événement de streaming en utilisant la méthode on()
de Node.js. Un événement de streaming permet à la méthode de consommer un morceau de données si un certain événement est émis. L’événement data
est déclenché lorsque les données transformées à partir de la méthode parse()
sont prêtes à être consommées. Pour accéder aux données, vous passez un rappel à la méthode on()
, qui prend un paramètre nommé row
. Le paramètre row
est un morceau de données transformé en un tableau. Dans le rappel, vous enregistrez les données dans la console en utilisant la méthode console.log()
.
Avant d’exécuter le fichier, vous ajouterez plus d’événements de flux. Ces événements de flux gèrent les erreurs et écrivent un message de succès dans la console lorsque toutes les données du fichier CSV ont été consommées.
Toujours dans votre fichier readCSV.js
, ajoutez le code surligné :
L’événement end
est émis lorsque toutes les données du fichier CSV ont été lues. Lorsque cela se produit, le rappel est invoqué et enregistre un message indiquant qu’il a terminé.
Si une erreur se produit n’importe où lors de la lecture et de l’analyse des données CSV, l’événement error
est émis, ce qui invoque le rappel et enregistre le message d’erreur dans la console.
Votre fichier complet devrait maintenant ressembler à ce qui suit :
Enregistrez et quittez votre fichier readCSV.js
en utilisant CTRL+X
.
Ensuite, exécutez le fichier en utilisant la commande node
:
La sortie ressemblera à ceci (éditée pour la brièveté) :
Output[
'2001-01',
'2020-09',
'Long-term migrant',
'Arrivals',
'Female',
'0-4 years',
'344',
'0',
'Final'
]
...
[
'2021-09',
...
'70',
'Provisional'
]
finished
Toutes les lignes du fichier CSV ont été transformées en tableaux à l’aide du flux de transformation csv-parse
. Comme la journalisation se produit chaque fois qu’un morceau est reçu du flux, les données semblent être téléchargées plutôt que d’être affichées toutes en une seule fois.
Dans cette étape, vous avez lu des données dans un fichier CSV et les avez transformées en tableaux. Ensuite, vous insérerez des données d’un fichier CSV dans la base de données.
Étape 3 — Insertion de données dans la base de données
Insérer des données à partir d’un fichier CSV dans la base de données en utilisant Node.js vous donne accès à une vaste bibliothèque de modules que vous pouvez utiliser pour traiter, nettoyer ou améliorer les données avant de les insérer dans la base de données.
Dans cette section, vous établirez une connexion avec la base de données SQLite en utilisant le module node-sqlite3
. Ensuite, vous créerez une table dans la base de données, copierez le fichier readCSV.js
et le modifierez pour insérer toutes les données lues à partir du fichier CSV dans la base de données.
Créez et ouvrez un fichier db.js
dans votre éditeur :
Dans votre fichier db.js
, ajoutez les lignes suivantes pour importer les modules fs
et node-sqlite3
:
Dans la troisième ligne, vous définissez le chemin de la base de données SQLite et le stockez dans la variable filepath
. Le fichier de base de données n’existe pas encore, mais il sera nécessaire pour que node-sqlite3
établisse une connexion avec la base de données.
Dans le même fichier, ajoutez les lignes suivantes pour connecter Node.js à une base de données SQLite :
Ici, vous définissez une fonction nommée connectToDatabase()
pour établir une connexion à la base de données. À l’intérieur de la fonction, vous invoquez la méthode existsSync()
du module fs
dans une déclaration if
, qui vérifie si le fichier de base de données existe dans le répertoire du projet. Si la condition if
est évaluée à true
, vous instanciez la classe Database()
de SQLite du module node-sqlite3
avec le chemin du fichier de base de données. Une fois que la connexion est établie, la fonction renvoie l’objet de connexion et se termine.
Cependant, si l’instruction if
est évaluée à false
(si le fichier de base de données n’existe pas), l’exécution passera au bloc else
. Dans le bloc else
, vous instanciez la classe Database()
avec deux arguments : le chemin du fichier de base de données et un rappel.
Le premier argument est le chemin du fichier de base de données SQLite, qui est ./population.db
. Le deuxième argument est un rappel qui sera invoqué automatiquement lorsque la connexion avec la base de données aura été établie avec succès ou en cas d’erreur. Le rappel prend un objet error
en paramètre, qui est null
si la connexion est réussie. À l’intérieur du rappel, l’instruction if
vérifie si l’objet error
est défini. Si elle est évaluée à true
, le rappel enregistre un message d’erreur et retourne. Si elle est évaluée à false
, vous enregistrez un message de réussite confirmant que la connexion a été établie.
Actuellement, les blocs if
et else
établissent l’objet de connexion. Vous passez un rappel lors de l’invocation de la classe Database
dans le bloc else
pour créer une table dans la base de données, mais seulement si le fichier de base de données n’existe pas. Si le fichier de base de données existe déjà, la fonction exécutera le bloc if
, se connectera à la base de données et renverra l’objet de connexion.
Pour créer une table si le fichier de base de données n’existe pas, ajoutez le code surligné :
Maintenant, la fonction connectToDatabase()
invoque la fonction createTable()
, qui accepte l’objet de connexion stocké dans la variable db
en tant qu’argument.
En dehors de la fonction connectToDatabase()
, vous définissez la fonction createTable()
, qui accepte l’objet de connexion db
en tant que paramètre. Vous invoquez la méthode exec()
sur l’objet de connexion db
qui prend une instruction SQL comme argument. L’instruction SQL crée une table nommée migration
avec 7 colonnes. Les noms des colonnes correspondent aux en-têtes du fichier migration_data.csv
.
Enfin, vous invoquez la fonction connectToDatabase()
et exportez l’objet de connexion retourné par la fonction afin qu’il puisse être réutilisé dans d’autres fichiers.
Enregistrez et quittez votre fichier db.js
.
Avec la connexion à la base de données établie, vous allez maintenant copier et modifier le fichier readCSV.js
pour insérer les lignes que le module csv-parse
a analysées dans la base de données.
Copiez et renommez le fichier en insertData.js
avec la commande suivante :
Ouvrez le fichier insertData.js
dans votre éditeur :
Ajoutez le code surligné :
Dans la troisième ligne, vous importez l’objet de connexion du fichier db.js
et le stockez dans la variable db
.
À l’intérieur du rappel d’événement data
attaché au flux du module fs
, vous invoquez la méthode serialize()
sur l’objet de connexion. La méthode garantit qu’une instruction SQL se termine avant qu’une autre ne commence, ce qui peut aider à prévenir les conditions de concurrence de la base de données où le système exécute simultanément des opérations concurrentes.
La méthode serialize()
prend un rappel. Dans le rappel, vous invoquez la méthode run
sur l’objet de connexion db
. La méthode accepte trois arguments :
-
Le premier argument est une instruction SQL qui sera transmise et exécutée dans la base de données SQLite. La méthode
run()
n’accepte que des instructions SQL qui ne renvoient pas de résultats. L’instructionINSERT INTO migration VALUES (?, ..., ?
insère une ligne dans la tablemigration
, et les?
sont des espaces réservés qui sont ensuite substitués par les valeurs dans le deuxième argument de la méthoderun()
. -
Le deuxième argument est un tableau
[row[0], ... row[5], row[6]]
. Dans la section précédente, la méthodeparse()
reçoit un morceau de données du flux lisible et le transforme en un tableau. Étant donné que les données sont reçues sous forme de tableau, pour obtenir la valeur de chaque champ, vous devez utiliser les index du tableau pour y accéder comme[row[1], ..., row[6]]
, etc. -
Le troisième argument est un rappel qui s’exécute lorsque les données ont été insérées ou si une erreur s’est produite. Le rappel vérifie si une erreur s’est produite et enregistre le message d’erreur. S’il n’y a pas d’erreurs, la fonction enregistre un message de réussite dans la console à l’aide de la méthode
console.log()
, vous informant qu’une ligne a été insérée avec l’identifiant.
Enfin, supprimez les événements end
et error
de votre fichier. En raison de la nature asynchrone des méthodes de node-sqlite3
, les événements end
et error
s’exécutent avant l’insertion des données dans la base de données, donc ils ne sont plus nécessaires.
Enregistrez et quittez votre fichier.
Exécutez le fichier insertData.js
à l’aide de node
:
En fonction de votre système, cela peut prendre un certain temps, mais node
devrait renvoyer la sortie ci-dessous:
OutputConnected to the database successfully
Inserted a row with the id: 1
Inserted a row with the id: 2
...
Inserted a row with the id: 44308
Inserted a row with the id: 44309
Inserted a row with the id: 44310
Le message, en particulier les identifiants, prouve que la ligne du fichier CSV a été enregistrée dans la base de données.
Vous pouvez maintenant lire un fichier CSV et insérer son contenu dans la base de données. Ensuite, vous écrirez un fichier CSV.
Étape 4 — Écriture de fichiers CSV
Dans cette section, vous récupérerez des données de la base de données et les écrirez dans un fichier CSV à l’aide de flux.
Créez et ouvrez writeCSV.js
dans votre éditeur:
Dans votre fichier writeCSV.js
, ajoutez les lignes suivantes pour importer les modules fs
et csv-stringify
ainsi que l’objet de connexion à la base de données depuis db.js
:
Le module csv-stringify
transforme les données d’un objet ou d’un tableau en format texte CSV.
Ensuite, ajoutez les lignes suivantes pour définir une variable contenant le nom du fichier CSV dans lequel vous souhaitez écrire les données et un flux inscriptible dans lequel vous allez écrire les données :
La méthode createWriteStream
prend un argument du nom de fichier dans lequel vous souhaitez écrire votre flux de données, qui est le nom de fichier saved_from_db.csv
stocké dans la variable filename
.
À la quatrième ligne, vous définissez une variable columns
, qui stocke un tableau contenant les noms des en-têtes des données CSV. Ces en-têtes seront écrits dans la première ligne du fichier CSV lorsque vous commencerez à écrire les données dans le fichier.
Toujours dans votre fichier writeCSV.js
, ajoutez les lignes suivantes pour récupérer les données de la base de données et écrire chaque ligne dans le fichier CSV :
Tout d’abord, vous invoquez la méthode stringify
avec un objet en argument, qui crée un flux de transformation. Le flux de transformation convertit les données d’un objet en texte CSV. L’objet passé à la méthode stringify()
a deux propriétés :
header
accepte une valeur booléenne et génère un en-tête si la valeur booléenne est définie surtrue
.columns
prend un tableau contenant les noms des colonnes qui seront écrites dans la première ligne du fichier CSV si l’optionheader
est définie surtrue
.
Ensuite, vous invoquez la méthode each()
de l’objet de connexion db
avec deux arguments. Le premier argument est l’instruction SQL select * from migration
qui récupère les lignes une par une dans la base de données. Le deuxième argument est un rappel invoqué à chaque fois qu’une ligne est récupérée de la base de données. Le rappel prend deux paramètres : un objet error
et un objet row
contenant les données récupérées d’une seule ligne dans la base de données. Dans le rappel, vous vérifiez si l’objet error
est défini dans l’instruction if
. Si la condition est évaluée à true
, un message d’erreur est enregistré dans la console à l’aide de la méthode console.log()
. S’il n’y a pas d’erreur, vous invoquez la méthode write()
sur stringifier
, qui écrit les données dans le flux de transformation stringifier
.
Lorsque la méthode each()
a terminé son itération, la méthode pipe()
sur le flux stringifier
commence à envoyer les données par petits morceaux et à les écrire dans le writableStream
. Le flux inscriptible sauvegardera chaque morceau de données dans le fichier saved_from_db.csv
. Une fois que toutes les données ont été écrites dans le fichier, console.log()
enregistrera un message de réussite.
Le fichier complet ressemblera maintenant à ce qui suit :
Enregistrez et fermez votre fichier, puis exécutez le fichier writeCSV.js
dans le terminal :
Vous recevrez la sortie suivante :
OutputFinished writing data
Pour confirmer que les données ont été écrites, inspectez le contenu du fichier en utilisant la commande cat
:
cat
renverra toutes les lignes écrites dans le fichier (édité pour des raisons de concision):
Outputyear_month,month_of_release,passenger_type,direction,sex,age,estimate
2001-01,2020-09,Long-term migrant,Arrivals,Female,0-4 years,344
2001-01,2020-09,Long-term migrant,Arrivals,Male,0-4 years,341
2001-01,2020-09,Long-term migrant,Arrivals,Female,10-14 years,
...
Vous pouvez désormais récupérer des données de la base de données et écrire chaque ligne dans un fichier CSV en utilisant des flux.
Conclusion
Dans cet article, vous avez lu un fichier CSV et inséré ses données dans une base de données en utilisant les modules node-csv
et node-sqlite3
. Vous avez ensuite récupéré des données de la base de données et les avez écrites dans un autre fichier CSV.
Vous pouvez maintenant lire et écrire des fichiers CSV. Ensuite, vous pouvez travailler avec de grands ensembles de données CSV en utilisant la même implémentation avec des flux efficaces en mémoire, ou vous pouvez examiner un package comme event-stream
qui facilite grandement le travail avec les flux.
Pour en savoir plus sur node-csv
, visitez leur documentation Projet CSV – Package CSV Node.js. Pour en savoir plus sur node-sqlite3
, consultez leur documentation Github. Pour continuer à développer vos compétences en Node.js, consultez la série Comment coder en Node.js.