Reputation: 143
I'm trying to find a solution for my previous post: Mongo gives duplicate key error on _id_ field in Meteor application
In order to do that I want to read data from my CSV file at server side, and not from the client.
First I tried the solution in this post Using node-csv and meteor-file to import CSV into a collection but meteor-file isn't compatible anymore with current version of Meteor. I also tried the solution in this post Upload Data to Meteor / Mongo DB but It's also on the client and that solution generates the same error as in my previous post.
After some further research I tried to read the data with the code below. However it doesn't work:
First I created a collection:
Meteor.orders = new Meteor.Collection('Orders');
I defined the following template to read the csv file:
<template name="read_file_orders">
<form class="well form-inline">
<label class="control-label" for="fileInput2">Kies bestand</label>
<input class="input-file" id="fileInput2" type="file" name="files[]">
<Button class="btn btn-primary" id="read_orders">Importeer</button>
<button class="btn btn-danger" id="erase_orders">Wis gegevens</button>
</form>
</template>
This is the client javascript:
Template.read_file_orders.events({
"click #read_orders" : function(e) {
var f = document.getElementById('fileInput2').files[0];
console.log("read file");
readFile(f, function(content) {
Meteor.call('upload',content);
});
}
});
readFile = function(f,onLoadCallback) {
var reader = new FileReader();
reader.onload = function (e){
var contents=e.target.result
onLoadCallback(contents);
}
reader.readAsText(f);
};
And this is the server javascript:
Meteor.startup(function () {
// code to run on server at startup
return Meteor.methods({
upload : function(fileContent) {
console.log("start insert");
import_file_orders(fileContent);
console.log("completed");
}
});
});
import_file_orders = function(file) {
var lines = file.split('%\r\n');
var l = lines.length - 1;
for (var i=0; i < l; i++) {
var line = lines[i];
var line_parts = line.split('|');
var ex_key = line_parts[0];
var ex_name = line_parts[1];
var clin_info = line_parts[2];
var order_info = line_parts[3];
var clinician_last_name = line_parts[4];
var clinician_first_name = line_parts[5];
var clinician_code = line_parts[6];
var clinician_riziv = line_parts[7]
var pat_id = line_parts[8];
Meteor.orders.insert({Patient:pat_id, Exam_code:ex_key, Exam_name:ex_name, Clinical_info:clin_info, Order_info:order_info, Clinician_first:clinician_first_name, Clinician_last:clinician_last_name, Clinician_c_code:clinician_code, Clinician_riziv:clinician_riziv, Planned:null});
console.log("%");
};
When I try reading the file, nothing happens. Only the console logs appear in the server console but there is nothing imported. Even the Orders collection isn't created.
It's clear that I'm doing something wrong but I don't know what exactly. However I think the solution isn't too far. Maybe someone of you can show me the right direction?
Kind regards
EDIT:
In order to revmen's answer here's the full code of my testapp:
test.html:
<head>
<title>test</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> read_file_orders}}
</body>
<template name="read_file_orders">
<form class="well form-inline">
<label class="control-label" for="fileInput2">Kies bestand</label>
<input class="input-file" id="fileInput2" type="file" name="files[]">
<Button class="btn btn-primary" id="read_orders">Importeer</button>
<button class="btn btn-danger" id="erase_orders">Wis gegevens</button>
</form>
</template>
test.js
Orders = new Mongo.Collection("orders");
if (Meteor.isClient) {
// counter starts at 0
Template.read_file_orders.events({
"click #read_orders" : function(e) {
var f = document.getElementById('fileInput2').files[0];
console.log("read file");
readFile(f, function(content) {
Meteor.call('upload',content);
});
}
});
import_file_orders = function(file) {
console.log("enter function import_file_orders")
var lines = file.split(/\r\n|\n/);
var l = lines.length - 1;
for (var i=0; i < l; i++) {
var line = lines[i];
var line_parts = line.split(',');
var ex_key = line_parts[0];
var ex_name = line_parts[1];
var clin_info = line_parts[2];
var order_info = line_parts[3];
var clinician_last_name = line_parts[4];
var clinician_first_name = line_parts[5];
var clinician_code = line_parts[6];
var clinician_riziv = line_parts[7]
var pat_id = line_parts[8];
var result = Orders.insert({Patient:pat_id, Exam_code:ex_key, Exam_name:ex_name, Clinical_info:clin_info, Order_info:order_info, Clinician:{first:clinician_first_name, last:clinician_last_name, c_code:clinician_code, riziv:clinician_riziv}, Planned:null});
console.log(Orders.findOne(result));
};
}
readFile = function(f,onLoadCallback) {
//When the file is loaded the callback is called with the contents as a string
var reader = new FileReader();
reader.onload = function (e){
var contents=e.target.result
onLoadCallback(contents);
}
reader.readAsText(f);
};
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
Meteor.methods({
upload : function(fileContent) {
console.log("start insert");
import_file_orders(fileContent);
console.log("completed");
}
});
}
Upvotes: 4
Views: 6288
Reputation: 563
You were very close. I just had to make a few changes to get it working.
I don't know what your .csv file looks like, so I made one that's like this:
A1, B1, C1, D1, E1, F1, G1, H1, I1
A2, B2, C2, D2, E2, F2, G2, H2, I2
Your file.split operation wasn't splitting the lines, but was putting everything on one big line. I did it this way and it worked:
var lines = file.split(/\r\n|\n/);
That got individual lines to split into members of the array. Then I assumed that, since you're calling your input a CSV, your values are separated by commas, not pipes. So I changed your line.split to this
var line_parts = line.split(',');
Other changes I made may not be what was causing yours to fail, but this is how I think things are normally done...
Instead of declaring your collection like this
Meteor.orders = new Meteor.Collection('Orders');
I did it like this
Orders = new Mongo.Collection("orders");
Note that this is run by both the server and the client.
Instead of your way of declaring methods on the server, I just put this into server code (not in Meteor.start):
Meteor.methods({
upload : function(fileContent) {
console.log("start insert");
import_file_orders(fileContent);
console.log("completed");
}
});
And, of course, I changed the insert line at the bottom of your import_file_orders function
var result = Orders.insert({Patient:pat_id, Exam_code:ex_key, Exam_name:ex_name, Clinical_info:clin_info, Order_info:order_info, Clinician_first:clinician_first_name, Clinician_last:clinician_last_name, Clinician_c_code:clinician_code, Clinician_riziv:clinician_riziv, Planned:null});
console.log(Orders.findOne(result));
EDIT for updated code in the question:
Move the import_file_orders function from the client block to the server block.
Upvotes: 6