Dit onderwerp is echt een plezierige voor mij. In veel webtoepassingen is het gebruikelijk om gebruikersinvoer te accepteren en één record in uw database op te slaan. Maar hoe zit het wanneer uw gebruikers (of u) meerdere invoegingen in één opdracht willen uitvoeren?
Geef dit artikel op, waarin wordt uitgelegd hoe u een CSV-sjabloon en een formulier kunt maken om het CSV-bestand te uploaden en hoe u de CSV kunt ontleden in een Mongoose-model dat wordt opgeslagen in een MongoDB-database.
In dit artikel wordt ervan uitgegaan dat je een basiskennis hebt van Mongoose en hoe het interageert met MongoDB. Als je dat niet doet, raad ik aan om eerst mijn artikel Introduction to Mongoose voor MongoDB en Node.js te lezen. In dit artikel wordt beschreven hoe Mongoose interageert met MongoDB door sterk getypeerde Schema's te maken waaruit een model is gemaakt. Als je al een goed begrip hebt van Mongoose, laten we doorgaan.
Laten we beginnen met het maken van een nieuwe Node.js-toepassing. Navigeer in een opdrachtprompt naar waar u uw Node.js-toepassingen wilt hosten en voer de volgende opdrachten uit:
mkdir csvimport cd csvimport npm init
Ik heb alle standaardinstellingen op mijn plaats gelaten, dus mijn toepassing zal beginnen index.js
. Voordat u CSV-bestanden kunt maken en parseren, moet eerst een eerste installatie worden uitgevoerd. Ik wil dit een webapplicatie maken; om dat te doen, ga ik het Express-pakket gebruiken om alle strikt noodzakelijke server-instellingen af te handelen. Installeer Express in de opdrachtprompt met de volgende opdracht:
npm install express --save
Omdat deze webapplicatie bestanden accepteert via een webformulier, ga ik ook het Express-subpakket Express-bestand uploaden gebruiken. Laten we dat nu ook installeren:
npm installeer express-fileupload - opslaan
Ik heb nu genoeg initiële configuratie gedaan om mijn webtoepassing in te stellen en een basiswebpagina te maken waarmee ik mijn bestanduploadformulier kan maken.
Hier is mijn index.js
bestand dat mijn webserver opzet:
var app = require ('express') (); var fileUpload = require ('express-fileupload'); var server = vereisen ('http') Server (app); app.use (FileUpload ()); server.listen (80); app.get ('/', functie (req, res) res.sendFile (__ dirname + '/index.html'););
Dit voorbeeld importeert Express en de Express File Upload-bibliotheken, configureert mijn webtoepassing om het uploaden van bestanden te gebruiken en luistert naar poort 80. Dit voorbeeld heeft ook een route gecreëerd met Express op "/", wat de standaard bestemmingspagina voor mijn web is toepassing. Deze route retourneert een index.html
bestand dat het webformulier bevat waarmee een gebruiker een CSV-bestand kan uploaden. In mijn geval werk ik op mijn lokale computer, dus wanneer ik http: // localhost bezoek, zal ik de vorm zien die ik in het volgende voorbeeld maak.
Hier is mijn index.html
pagina die mijn formulier maakt voor het uploaden van een CSV-bestand:
Upload auteurs Gebruik het onderstaande formulier om een lijst met auteurs te uploaden. Klik hier voor een voorbeeldsjabloon.
Dit HTML-bestand bevat twee belangrijke zaken:
eNCTYPE
instellen als multipart / form-data
en een invoerveld met een type het dossier
dat accepteert bestanden met een "csv" extensie.Zoals je misschien hebt gemerkt, verwijst de HTML naar een sjabloon van een auteur. Als je mijn artikel Introduction to Mongoose leest, heb ik een Author Schema gemaakt. In dit artikel ga ik dit Schema opnieuw maken en de gebruiker toestaan om een verzameling auteurs massaal in mijn MongoDB-database te importeren. Laten we het Schema van de auteur bekijken. Voordat we dat echter doen, heb je het waarschijnlijk al geraden: we moeten het Mongoose-pakket installeren:
npm mongoose installeren - opslaan
Met Mongoose geïnstalleerd, laten we een nieuw maken author.js
bestand dat het Auteursschema en -model zal definiëren:
var mongoose = vereisen ('mongoose'); var authorSchema = mongoose.Schema (_id: mongo.Schema.Types.ObjectId, name: firstName: type: String, required: true, lastName: String, biography: String, twitter: type: String, validate : validator: function (text) if (text! == null && text.length> 0) return text.indexOf ('https://twitter.com/') === 0; return true;, bericht : 'Twitter-handvat moet beginnen met https://twitter.com/', facebook: type: String, valideren: validator: functie (tekst) if (text! == null && text.length> 0) return text.indexOf ('https://www.facebook.com/') === 0; return true;, bericht: 'Facebook Page moet beginnen met https://www.facebook.com/', linkedin: type: String, valideren: validator: functie (tekst) if (text! == null && text.length> 0) return text.indexOf ('https://www.linkedin.com/') = == 0; return true;, bericht: 'LinkedIn moet beginnen met https://www.linkedin.com/', profilePicture: Buffer, aangemaakt: type: Date, default: Date.now); var Auteur = mongoose.model ('Auteur', auteur Schema); module.exports = Auteur;
Met het auteursschema en het gemaakte model kunnen we schakelen en ons richten op het maken van de CSV-sjabloon die kan worden gedownload door op de sjabloonkoppeling te klikken. Als hulp bij het genereren van de CSV-sjabloon ga ik het pakket JSON naar CSV gebruiken. Laten we dat nu installeren:
npm installeer json2csv --save
Ik ga nu mijn eerder gemaakte update updaten index.js
bestand om een nieuwe route voor "/ sjabloon" op te nemen:
var template = require ('./ template.js'); app.get ('/ template', template.get);
Ik heb alleen de nieuwe code toegevoegd voor de sjabloonroute die aan de vorige is toegevoegd index.js
het dossier.
Het eerste dat deze code doet, is een nieuw template.js
bestand (wordt hierna aangemaakt) en maak een route voor "/ sjabloon". Deze route roept een krijgen
functie in de template.js
het dossier.
Nadat de Express-server is bijgewerkt met de nieuwe route, maken we de nieuwe template.js
het dossier:
var json2csv = require ('json2csv'); exports.get = function (req, res) var fields = ['name.firstName', 'name.lastName', 'biography', 'twitter', 'facebook', 'linkedin']; var csv = json2csv (data: ", fields: fields); res.set (" Content-Disposition "," attachment; filename = authors.csv "); res.set (" Content-Type "," application / octet-stream "); res.send (csv);;
Dit bestand bevat eerst de eerder geïnstalleerde json2csv
pakket. Ik maak en exporteer vervolgens een krijgen
functie. Deze functie accepteert de aanvraag- en reactieobjecten van de Express-server.
Binnen de functie heb ik een array met de velden gemaakt die ik in mijn CSV-sjabloon wil opnemen. Dit kan op twee manieren worden gedaan. De eerste manier (die in dit voorbeeld wordt gedaan) is om een statische lijst te maken van de velden die in de sjabloon moeten worden opgenomen. De tweede manier is om de lijst met velden dynamisch te maken door de eigenschappen uit het auteursschema te extraheren.
De tweede manier zou kunnen worden gedaan met de volgende code:
var fields = Object.keys (Author.schema.obj);
Ik had graag deze dynamische methode willen gebruiken, maar het wordt een beetje ingewikkeld als ik niet meerdere eigenschappen van het Schema wil opnemen in mijn CSV-sjabloon. In dit geval bevat mijn sjabloon de _ID kaart
en aangemaakt
eigenschappen omdat deze worden ingevuld via code. Als u echter geen velden hebt die u wilt uitsluiten, werkt de dynamische methode ook.
Met de reeks gedefinieerde velden gebruik ik de json2csv
pakket om mijn CSV-sjabloon van mijn JavaScript-object te maken. Deze csv
object zullen de resultaten van deze route zijn.
En tot slot, met behulp van de res
eigenschap van de Express-server, heb ik twee header-eigenschappen ingesteld die het downloaden van een authors.csv
het dossier.
Als u op dit moment uw Node-toepassing zou uitvoeren en naar http: // localhost in uw webbrowser zou gaan, zou het webformulier worden weergegeven met een koppeling om de sjabloon te downloaden. Als u op de koppeling klikt om de sjabloon te downloaden, kunt u de authors.csv
bestand dat moet worden ingevuld voordat het wordt geüpload.
Hier is een voorbeeld van een bevolkt CSV-bestand:
name.firstName, name.lastName, biografie, twitter, facebook, linkedin Jamie, Munro, Jamie is een webontwikkelaar en auteur ,,, Mike, Wilson, Mike is een webontwikkelaar en auteur van Node.js,,,
Als dit voorbeeld wordt geüpload, worden twee auteurs gemaakt: ikzelf en een vriend die een paar jaar geleden een boek schreef over Node.js. Het kan je opvallen dat aan het einde van elke regel drie komma's ",,," staan. Dit wordt gedaan om het voorbeeld af te korten. Ik heb de sociale netwerkeigenschappen niet ingevuld (tjilpen
, facebook
, en linkedin
).
De puzzelstukjes beginnen samen te komen en vormen een foto. Laten we naar het vlees en de aardappelen van dit voorbeeld gaan en dat CSV-bestand analyseren. De index.js
bestand vereist wat updates om verbinding te maken met MongoDB en een nieuwe POST-route te maken die het uploaden van het bestand accepteert:
var app = require ('express') (); var fileUpload = require ('express-fileupload'); var mongoose = vereisen ('mongoose'); var server = vereisen ('http') Server (app); app.use (FileUpload ()); server.listen (80); mongoose.connect ( 'MongoDB: // localhost / csvimport'); app.get ('/', functie (req, res) res.sendFile (__ dirname + '/index.html');); var template = require ('./ template.js'); app.get ('/ template', template.get); var upload = require ('./ upload.js'); app.post ('/', upload.post);
Met een databaseverbinding en een nieuwe POST-route geconfigureerd, is het tijd om het CSV-bestand te ontleden. Gelukkig zijn er verschillende geweldige bibliotheken die helpen met deze taak. Ik heb ervoor gekozen om de fast-csv
pakket dat kan worden geïnstalleerd met de volgende opdracht:
npm installeer fast-csv --save
De POST-route is op dezelfde manier gemaakt als de sjabloonroute die a aanroept post
functie van de upload.js
het dossier. Het is niet nodig om deze functies in afzonderlijke bestanden te plaatsen; Ik maak echter graag afzonderlijke bestanden voor deze routes omdat dit helpt de code mooi en georganiseerd te houden.
En tot slot, laten we de upload.js
bestand met de post
functie die wordt aangeroepen wanneer het eerder gemaakte formulier wordt verzonden:
var csv = require ('fast-csv'); var mongoose = vereisen ('mongoose'); var Auteur = require ('./ author'); exports.post = functie (req, res) if (! req.files) return res.status (400) .send ('Geen bestanden geüpload.'); var authorFile = req.bestanden.bestand; var authors = []; csv .fromString (authorFile.data.toString (), headers: true, ignoreEmpty: true) .on ("data", functie (data) data ['_ id'] = new mongoose.Types.ObjectId (); authors.push (data);) .on ("end", function () Author.create (authors, function (err, documents) if (err) gooi err;); res.send (authors.length + 'auteurs zijn succesvol geüpload.');); ;
Er gebeurt nogal wat in dit bestand. De eerste drie regels bevatten de benodigde pakketten die nodig zijn om de CSV-gegevens te ontleden en op te slaan.
Vervolgens de post
functie is gedefinieerd en geëxporteerd voor gebruik door de index.js
het dossier. Binnen deze functie vindt de betovering plaats.
De functie controleert eerst of er een bestand is in de behuizing van het verzoek. Als dit niet het geval is, wordt een fout geretourneerd die aangeeft dat een bestand moet worden geüpload.
Wanneer een bestand is geüpload, wordt een verwijzing naar het bestand opgeslagen in een variabele met de naam authorFile
. Dit wordt gedaan door toegang te krijgen tot de bestanden
array en de het dossier
eigenschap in de array. De het dossier
eigenschap komt overeen met de naam van mijn bestandsinvoer naam die ik voor het eerst heb gedefinieerd in de index.html
voorbeeld.
Ik heb ook een gemaakt auteurs
array die wordt gevuld als het CSV-bestand wordt geparseerd. Deze array wordt gebruikt om de gegevens in de database op te slaan.
De fast-csv
bibliotheek wordt nu gebeld door gebruik te maken van de fromString
functie. Met deze functie accepteert u het CSV-bestand als een tekenreeks. Ik heb de string uit de authorFile.data
eigendom. De gegevens
property bevat de inhoud van mijn geüploade CSV-bestand.
Ik heb twee opties toegevoegd aan de fast-csv
functie: headers
en ignoreEmpty
. Deze zijn beide ingesteld op waar
. Dit vertelt de bibliotheek dat de eerste regel van het CSV-bestand de kopteksten bevat en dat lege rijen moeten worden genegeerd.
Met de geconfigureerde opties, heb ik twee listener-functies ingesteld die worden aangeroepen wanneer de gegevens
evenement en de einde
gebeurtenis wordt geactiveerd. De gegevens
event wordt eenmaal voor elke rij van het CSV-bestand aangeroepen. Deze gebeurtenis bevat een JavaScript-object van de geparseerde gegevens.
Ik werk dit object bij met de _ID kaart
eigendom van de auteur Schema met een nieuwe ObjectId
. Dit object wordt vervolgens toegevoegd aan de auteurs
rangschikking.
Wanneer het CSV-bestand volledig is geparseerd, wordt de einde
gebeurtenis is geactiveerd. Binnen de callback-functie van het evenement, bel ik de creëren
functioneert op het Auteur-model en geeft de reeks door auteurs
ernaar toe.
Als er een fout optreedt bij het proberen de array op te slaan, wordt een uitzondering gegenereerd; anders wordt een succesbericht weergegeven aan de gebruiker die aangeeft hoeveel auteurs zijn geüpload en opgeslagen in de database.
Als je de volledige broncode wilt zien, heb ik een GitHub-repository met de code gemaakt.
In mijn voorbeeld heb ik slechts een aantal records geüpload. Als u in uw use-case duizenden records kunt uploaden, is het wellicht een goed idee om de records in kleinere delen op te slaan.
Dit kan op verschillende manieren worden gedaan. Als ik het zou implementeren, zou ik willen voorstellen het gegevens
callback-functie om de lengte van de auteurs-array te controleren. Wanneer de array uw gedefinieerde lengte overschrijdt, b.v. 100, bel de Author.create
op de array en stel vervolgens de array opnieuw in op leeg. Dit zal dan de records in stukken van 100 opslaan. Zorg ervoor dat u de finale verlaat creëren
bel in de einde
callback-functie om de definitieve records op te slaan.
Genieten!