question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Upload CSV to Keystone Database

See original GitHub issue

I am trying to upload a csv file via an upload button in Keystone Admin UI to insert the content of the CSV file into the mongodb database.

For example, I have a blog post CSV file and I want to upload it to the Post table in the Keystonejs database.

Such upload button does not exist so I have to create one beside the existing Create Post button.

image

Also I have to make some csv to mongodb logic code and put it to somewhere.

I am hoping someone here using Keystone can give me a bit direction on how to implement this upload button and update mongodb logic as in where/which file to put the code?

To me right now, it looks like the path /node_modules/keyston/admin/src/views is the place to go. Am I right?

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:15 (4 by maintainers)

github_iconTop GitHub Comments

5reactions
xianlincommented, Jun 8, 2015

Finally I got it done. (It will delete the original list data though, you are warned)

I hope my work can help someone who want this CSV upload feature.

Here is the code/meat/HowTo:

modify the keystone/admin/src/views/list.js, I am ONLY allow upload csv for Post list, you can use your own list.


   var React = require('react');
var CreateForm = require('../components/CreateForm');
var UploadForm = require('../components/UploadForm');

var View = React.createClass({

    displayName: 'ListView',

    getInitialState: function() {
        return {
            createIsVisible: Keystone.showCreateForm,
            uploadIsVisible: Keystone.showUploadForm,
            animateCreateForm: false,
            animateUploadForm: false
        };
    },

    toggleCreate: function(visible) {
        this.setState({
            createIsVisible: visible,
            animateCreateForm: true
        });
    },

    toggleUpload: function(visible) {
        this.setState({
            uploadIsVisible: visible,
            animateUploadForm: true
        });
    },

    renderCreateButton: function() {
        if (Keystone.list.autocreate) {
            return (
                <a href={'?new' + Keystone.csrf.query} className="btn btn-default btn-create btn-create-item">
                    <span className="ion-plus-round mr-5" />
                    Create {Keystone.list.singular}
                </a>
            );
        }
        return (
            <button type="button" className="btn btn-default btn-create btn-create-item" onClick={this.toggleCreate.bind(this, true)}>
                <span className="ion-plus-round mr-5" />
                Create {Keystone.list.singular}
            </button>
        );
    },

    renderCreateForm: function() {
        if (!this.state.createIsVisible) return null;
        return <CreateForm list={Keystone.list} animate={this.state.animateCreateForm} onCancel={this.toggleCreate.bind(this, false)} values={Keystone.createFormData} err={Keystone.createFormErrors} />;
    },

    renderUploadButton: function() {
        if (Keystone.list.singular === 'Post') {
            return (
                <button type="button" className="btn btn-default btn-create btn-create-item" onClick={this.toggleUpload.bind(this, true)}>
                    <span className="ion-plus-round mr-5" />
                    Upload CSV for {Keystone.list.singular}
                </button>
            );
        }
    },

    renderUploadForm: function() {
        if (!this.state.uploadIsVisible) return null;
        return <UploadForm list={Keystone.list} animate={this.state.animateCreateForm} onCancel={this.toggleUpload.bind(this, false)} />;
    },

    render: function() {
        if (Keystone.list.nocreate) return null;
        return (
            <div className="create-item">
                <div className="toolbar">
                    {this.renderCreateButton()}
                    {this.renderUploadButton()}
                </div>
                {this.renderCreateForm()}
                {this.renderUploadForm()}
                <hr />
            </div>
        );
    }

});

React.render(<View />, document.getElementById('list-view'));

Add a new UploadForm by create keystone/admin/src/components/UploadForm.js, please note the form submit action can be customized, mine is /uploadcsv_post.


var _ = require('underscore'),
    React = require('react');

var Form = React.createClass({

    displayName: 'UploadForm',

    render: function() {

        var list = this.props.list;
        var modalClass = 'modal modal-md' + (this.props.animate ? ' animate' : '');

        return (
            <div>
                <div className={modalClass}>
                    <div className="modal-dialog">
                        <form className="modal-content" encType="multipart/form-data" method="post" action='/uploadcsv_post'>
                            <input type="hidden" name="action" value="create" />
                            <input type="hidden" name={Keystone.csrf.key} value={Keystone.csrf.value} />
                            <div className="modal-header">
                                <button type="button" className="modal-close" onClick={this.props.onCancel}></button>
                                <div className="modal-title">Upload CSV for {list.singular}</div>
                            </div>
                            <div className="modal-body">
                                CSV File:<input type="file" id="csvFile" accept=".csv" name="csvFile"/>  
                            </div>
                            <div className="modal-footer">
                                <button type="submit" name="submit" className="btn btn-create">Upload</button>
                                <button type="button" className="btn btn-link btn-cancel" onClick={this.props.onCancel}>cancel</button>
                            </div>
                        </form>
                    </div>
                </div>
                <div className="modal-backdrop"></div>
            </div>
        );
    }

});

module.exports = Form;

Continue to add /uploadcsv_post logic to keystone route, create routes/api/uploadcsv.js, please note that I added my own customized json parser to suit my own CSV file format, you should modify it to suit your needs.

/**
 * Upload CSV for Posts
 */

var keystone = require('keystone'),
  _ = require('underscore'),
  Menu = keystone.list('Post');

exports = module.exports = function(req, res) {
    var Converter=require("csvtojson").core.Converter;
    var fs=require("fs");
    //CSV File Path or CSV String or Readable Stream Object
    var csvFileName=req.files.csvFile.path;
    var fileStream=fs.createReadStream(csvFileName);
    //new converter instance
    var csvConverter=new Converter({constructResult:true});

    //end_parsed will be emitted once parsing finished
    csvConverter.on("end_parsed",function(jsonObj){
      //res.json(jsonObj);
      var postJson = _.each(jsonObj, function(value,key){
        value.date = new Date(value.date).toISOString().slice(0, 10);
      });
      console.log(postJson);
      Post.model.find({}).remove().exec();
      keystone.createItems({
        Post: postJson
      },function(err, stats) {
        if (err) return res.json(err);
        //stats && console.log(stats.message);
        res.redirect('/keystone/posts');
      });
    });

    //read from file
    fileStream.pipe(csvConverter);
}

Don’t forget to change the route at routes/index.js with below code:

 app.post('/uploadcsv_post', keystone.middleware.cors, routes.api.uploadcsv);

Also install csvtojson:

npm install csvtojson --save

I hope someone can use it or even better, integrate this feature into Keystone.js.

0reactions
Rajivkumar1234commented, Aug 13, 2019

@xianlin , you could reduce your csv to json with the ff code


var csv = require("csvtojson");
  var csvFilePath=req.files.csvFile.path;

  csv()
  .fromFile(csvFilePath)
  .then(function(jsonArrayObj){ //when parse finished, result will be emitted here.
     console.log("jsonArrayObj", jsonArrayObj); 
   })
Read more comments on GitHub >

github_iconTop Results From Across the Web

CSV Import · Issue #150 · keystonejs/keystone-classic - GitHub
Ok, we have CSV Export and Download, how about CSV Import? I'm working on a rewrite of a small local website and am...
Read more >
How to upload a file to KeystoneJS server - Stack Overflow
I'm trying to upload a csv file to KeystoneJS (I want to parse the rows and add the records to my MongoDB), but...
Read more >
Keystone CSV File Specification
Employer Earned Income Tax (EIT) Upload. Comma-separated (.CSV) File Format. USE COMMAS AS FIELD SEPARATORS ONLY. DO NOT USE COMMAS WITHIN A DATA...
Read more >
Keystone Js | Excellence Technologies
For download or export of the saved data stored in database, keystone provide a method getCSVData . that's allow which field should include...
Read more >
LOAD a CSV - Vertica Forum
I have a problem when I want to load one .csv file, I did this STEP 1 create table prueba(Id VARCHAR(100),Sepal_Length FLOAT,Sepal_Width ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found