Skip to content

Instantly share code, notes, and snippets.

@grncdr
Created June 17, 2015 22:29
Show Gist options
  • Star 35 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save grncdr/9458c230ac838d73a559 to your computer and use it in GitHub Desktop.
Save grncdr/9458c230ac838d73a559 to your computer and use it in GitHub Desktop.
Demo of importing a CSV file into a Contentful space
first name last name age
Stephen Sugden 31
Tom Reznik 29
Justin Thomas 30
#!/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);
});
{
"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"
}
}
@duffy-walsh
Copy link

In case anyone is a late comer to this like myself, the value of the contentTypeId should be the human readable form. For example, instead of something like '5aL1iEoPWE44KAcwUOw8M6', it should be 'person' or the corresponding value.

@ralphilius
Copy link

Other note, you need to use babel-cli to compile the code so that it can be run with node 6.x.x. Otherwise, run it with babel-node

@rtuttlecoder
Copy link

how does one properly format an Array or RichText for this csv import?

@dsacramone
Copy link

@rtuttlecoder Did you end up finding a solution/answer to your question? Did you end up using a diff script?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment