Search code examples
javascriptcsvcontent-management-systemsanity

How to import CSV to sanity.io


Im a hobby programmer exploring the free version of the new headless CMS sanity (www.sanity.io).

Bumping into a problem when trying to upload / import data into my project: Is there a way to import data from a csv file? Example from docs only explain json files: https://www.sanity.io/docs/content-studio/importing-data

Instead of explaining my own project, let me use the bundled movie studio as an example: Say that I would like to add a layer of information being which Film Studio made the movies. I have a CSV file with a list of studios, with columns being Name, Country, webpage, CEO, Movies. Where the final is an array with name of movies from that studio. I would like to import this CSV to create a new content type being studio, where the list of studios is populated, and where the movie array is references, not text.

Can anyone help me understand how I should go about doing hit?


Solution

  • There is currently no way to import data directly from a CSV file to Sanity. Still, achieving what you want is pretty straight forward. Briefly, this is want you'll want to do:

    1. Parse CSV file
    2. Structure incoming data to match you schema
    3. Write new documents to a newline-delimited JSON file
    4. Import that file to Sanity

    Say your CSV file named studios.csv looks something like this:

    NAME,WEBPAGE,MOVIES
    Paramount,paramountstudios.com,Ghost in the Shell;Arrival
    DreamWorks,dreamworksstudios.com,Ghost in the Shell;Minority Report;Transformers
    

    The below code uses csv-parser, but it should still serve as an example if you want to use some other package for gobbling CSV.

    const csv = require('csv-parser')
    const fs = require('fs')
    const sanityClient = require('@sanity/client')
    const client = sanityClient({
      projectId: 'my-project-id',
      dataset: 'my-dataset',
      useCdn: false
    })
    
    function appendToFile(document) {
      const docAsNewLineJson = `${JSON.stringify(document)}\n`
      fs.appendFileSync('ready-for-import.ndjson', docAsNewLineJson, {flag: 'a+'})
    }
    
    function moviesByTitles(titles) {
      return client.fetch('*[_type == "movie" && title in $titles]', {titles: titles})
    }
    
    fs.createReadStream('studios.csv')
      .pipe(csv())
      .on('data', data => {
        // Assuming movie titles are semi-colon separated
        const titles = data.MOVIES.split(';')
        // Fetch movies with these titles 
        moviesByTitles(titles).then(movies => {
          // Build a Sanity document which matches your Studio type
          const document = {
            _type: 'studio',
            name: data.NAME,
            webPage: data.WEBPAGE,
            movies: movies.map(movie => {
              return {
                _ref: movie._id,
                _type: 'reference'
              }
            })
          }
          // Append the document to a file for later import
          appendToFile(document)  
        )}
      })
    

    You'll end up with the file ready-for-import.ndjson containing Sanity documents ready for import, so now you can simply:

    sanity dataset import ready-for-import.ndjson <my-dataset>
    

    It might prove useful to include an _id field with a unique, non-random value on each studio, e.g. studio_${data.NAME.toLowerCase().replace(' ', '-')}. This will allow you to import your documents multiple times (using the --replace flag), without getting duplicates.