Skip to content

Instantly share code, notes, and snippets.

@grncdr
Created June 17, 2015 22:29

Revisions

  1. grncdr created this gist Jun 17, 2015.
    4 changes: 4 additions & 0 deletions data.csv
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,4 @@
    first name,last name,age
    Stephen,Sugden,31
    Tom,Reznik,29
    Justin,Thomas,30
    71 changes: 71 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    #!/usr/bin/env babel-node --stage=0

    import fs from 'fs';
    import contentful from 'contentful-management';
    import Parser from 'csv-parse';
    import prat from 'prat';

    const client = contentful.createClient({
    /**
    * Your Management API token. Get one quickly at
    * contentful.com/developers/documentation/content-management-api
    * then set it as an environment variable like
    *
    * export CONTENTFUL_CMA_TOKEN="abcdef123457890"
    */
    accessToken: process.env.CONTENTFUL_CMA_TOKEN,
    });

    /**
    * The Content Type ID that matches the rows from the CSV you want to import
    */
    const contentTypeId = '5aL1iEoPWE44KAcwUOw8M6';

    async function main () {
    const space = await client.getSpace('n65xuot4ik7f');
    const parser = new Parser({columns: true});
    const rows = fs.createReadStream('./data.csv').pipe(parser);
    const entries = await prat.ify(rows)
    .map((row) => rowToEntry(space, row))
    .reduce([], (entries, entry) => entries.concat(entry));
    console.log('entries', entries)
    }

    /**
    * Finds an entry and updates it, or creates a new entry if no existing entry is found.
    *
    * The update logic simply overwrites the existing fields, a deep merge would
    * be a better strategy if the entries also have fields that are edited by humans.
    */
    async function rowToEntry (space, row) {
    const id = `${row['first name']}.${row['last name']}`;
    const sys = { id };
    const fields = rowToFields(row);
    try {
    const entry = await space.getEntry(id)
    entry.fields = fields;
    console.log('Update', id);
    return await space.updateEntry(entry);
    } catch (_) {
    console.log('Create', id);
    return await space.createEntry(contentTypeId, { sys, fields });
    }
    }

    /**
    * This helper maps a CSV row to the contentful fields structure.
    * Currently it's hard-coded to use en-US, but expanding this script to support
    * multiple locales (maybe by importing different files) would be trivial.
    */
    function rowToFields (row) {
    return {
    firstName: { 'en-US': row['first name'] },
    lastName: { 'en-US': row['last name'] },
    age: { 'en-US': parseInt(row['age'], 10) }
    };
    }

    main().catch((err) => {
    console.error(err.stack);
    process.exit(1);
    });
    18 changes: 18 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    {
    "name": "example-contentful-csv-import",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
    "test": "echo \"Tests? maybe next time ;)\" && exit 1",
    "import": "babel-node --stage=0 index.js"
    },
    "author": "Stephen Sugden",
    "license": "MIT",
    "dependencies": {
    "babel": "^5.5.8",
    "contentful-management": "^0.1.1",
    "csv": "^0.4.5",
    "prat": "^1.1.0"
    }
    }