4

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");
 }
});

}
Community
  • 1
  • 1
Quantum
  • 143
  • 4
  • 10
  • I am using the same code but unfortunately, I am receiving a non-human-readable text at the reader.readAsText(f); Is there any way to parse it? – Anand Vaidya Apr 18 '18 at 10:30

1 Answers1

6

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.

RevMen
  • 562
  • 3
  • 14
  • I tried this solution, but unfortunately, without success. Nothing happens. – Quantum Mar 16 '15 at 16:01
  • Worked great for me! Can you post a few lines from your data file so we can see what you're trying to import? – RevMen Mar 16 '15 at 22:29
  • I have created a CSV file like that in your post. I think there must be something wrong very essentially with my code. It seems that the import function isn't executed. I have created a small test application to test your solution. May I post the code in EDIT in my initial post? – Quantum Mar 17 '15 at 08:42
  • Go for it. Be sure to note what files and directories your code is in, too. – RevMen Mar 17 '15 at 14:30
  • You have your import_file_orders function in the Meteor.isClient block. I moved it to the Meteor.isServer where the upload method can see it and now it runs. – RevMen Mar 17 '15 at 21:14
  • I tried this code again and now it works anymore. I have no idea why and I'm tired to search. The problem is that the Meteor.call function isn't fired inside the readFile block. Even if I want to fire a simple test method that prints "hello world" in the console it doesn't work. However the same method fires when I place it outside the readFile block. I totally confused and pissed because it was working earlier. – Quantum Mar 26 '15 at 11:16
  • OK, I found the problem. When I read the data in Chromium browser all looks clear. When I do the same in Firefox it doesn't work. So it seems that the code is interpreted different in both browsers. – Quantum Mar 26 '15 at 15:24