How to send multiple image as response in node.js - javascript

i have stored more image in mongodb by using like this
exports.save = function (input, image, callback)
{
db.collection("articles", function (error, collection)
{
collection.save(input, {safe: true}, callback);
});
}
i have retrieved all image from db.
find().toArray(function(err,result)
{
console.log(result.length)//length is 5
for(var i=0;i<results.length;i++)
{
res.contentType(results[i].imageType);
res.end(results[i].image.buffer, "binary");
}
});
how to convert this image as binary and how to send response to client.i have tried for loop but i got this error can't set header after send res.........how to solve

There is no way to send multiple images within a one single response, I guess. But maybe you could try to merge those images somehow within your loop, and then send a one big image which will consists of your N images merged together.

I have just had a similar problem. You need to pass your 'results' array to a Jade template (for example) or manually create an HTML page with the images that you find (not the data) - rather virtual links to the actual images.
res.render('image_list.jade', {results:results});
Then your template might look like :
block content
div.container
header
h1 Images in a list
div#images
- each result in results
div.myimage
img(src='http://localhost:3000/oneimage'+result._id)
In your app.js you would need to provide a route /oneimage that returns a single image (data) as you have done in your code (i.e replace findAll(...) with findOne(...., id, ...)

Related

Node.js- Make JSON Array object in the server side available to HTML page for D3 charts

I'm very new to Node.js. My goal is to develop d3 charts in HTML handling Data objects(Json Array) that have 100K plus rows using a CSV spreadsheet. I want to load the CSV file and convert it to JSON Array object in the server side so this will not crash IE11 when loading the CSV file in the front end. The CSV is a big file. When I create a node js file that creates a server and load/convert the CSV into JSON Array using require('csvtojson') module, I want to send the JSON Array object to my html so i can grab that object and plug into D3 charts. I'm trying to avoid having the "Not enough storage..." jquery error when using ajax. Is this possible? I'm trying really hard to find an example but no luck. Only sites i found is how to display the json as a string into the html page. Is there a way to grab the JSON Array object in the HTML page? This is the code i use to create a server and to make all my html pages display on the browser.
Updated: I added the csv() and it converts the data into jsonObject. So far its just getting the one json object which this is not the case. I just want to push the 'jsonData' object so i can grab that in the HTML page and plug it to d3. Is this possible? Please, need help. I cant use d3.csv() in html because the file is too large and the IE11 browser will crash. Thats why I do this in the server.
csv().fromFile(csvFilePath)
.on('json', (jsonObj) => {
console.log(jsonObj);
jsonData = jsonObj;
})
.on('done', (error) => {
console.log('end');
}); http.createServer(function (req, res) {
var q = url.parse(req.url, true);
var filename = "." + q.pathname;
fs.readFile(filename, function(err, html) {
if(err) {
res.writeHead(404, {'Content-Type': 'text/html'});
return res.end('404 Not Found');
}
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(html);
return res.end();
});
}).listen(8080);
Is there a way to have the JSON Array object available when I load the HTML page and grab the object to plus into d3?
Also I tried this method but it didnt work which I open this question awhile back:
Not enough storage error when using Ajax. Large response
Thank you. I tried explaining the best i can. Please need help..

How to load multiple files with Queue.js and D3.js?

Situation
I am trying to load multiple xml files (located on server) without the need to declare the name of the files hard coded. For this I am trying to use the d3.queue library https://github.com/d3/d3-queue.
I have implemented the xml to force layout to my own needs (https://bl.ocks.org/mbostock/1080941), but there is one crucial flaw namely I need to manually type in the name of the xml file that I want to load...
Reproduce
Given (adjusted example from http://learnjsdata.com/read_data.html) :
queue()
.defer(d3.xml, "/mappings/Customer.hbm.xml")
.defer(d3.xml, "/mappings/Actor.hbm.xml")
.await(analyze);
function analyze(error, Customer, Actor) {
if(error) { console.log(error); }
// do stuff with Customer data, do stuff with Actor data
}
And given my implementation of the processing of an xml:
d3.xml("mappings/Customer.hbm.xml","application/xml", function(error,xml){
if (error) throw error;
// do stuff with the data retrieved from Customer.hbm.xml
});
Question
How do I combine above two snippets in such a way that I dont have to write the locations of the xml hard coded and pass all the parameters to the analyze function? Any nudge in the right direction would be much appreciated.
In psuedocode I have tried to code something like the following (but I cant get it to work):
function to get all names of the xmls from the mappings folder (probably with node.js fs.readdir or fs.readdirSync methods, but I am unsure of how that would work exactly)
for each xml .defer(d3.xml, nameofxml)
pass all the found names as parameters to the analyze function
In Java I would have chosen to do this with a var...args but I dont know how to do it in JS.
There's really two parts to this question:
How do I get a list of server-side files to client-side JavaScript?
Short answer is you don't without having a server-side api that can return that list. Depending on what backend you are using, you write a method that returns a JSON array of the files in your target directory. You call this first, get the response and then process them all with queue:
d3.json('/get/list/of/xml/files', function(error, fileArray){
var q = d3.queue();
fileArray.forEach(function(d){
q = q.defer(d3.xml, d);
});
q.await(analyze);
});
How do a process a variable number of arguments in JavaScript?
This is actually very well supported in JavaScript.
function analyze(error) {
if(error) { console.log(error); }
// skip 0 it's error variable
for (i = 1; i < arguments.length; i++) {
var xml = arguments[i];
...
}
}

MongoDb bulk insert limit issue

Im new with mongo and node. I was trying to upload a csv into the mongodb.
Steps include:
Reading the csv.
Converting it into JSON.
Pushing it to the mongodb.
I used 'csvtojson' module to convert csv to json and pushed it using code :
MongoClient.connect('mongodb://127.0.0.1/test', function (err, db) { //connect to mongodb
var collection = db.collection('qr');
collection.insert(jsonObj.csvRows, function (err, result) {
console.log(JSON.stringify(result));
console.log(JSON.stringify(err));
});
console.log("successfully connected to the database");
//db.close();
});
This code is working fine with csv upto size 4mb; more than that its not working.
I tried to console the error
console.log(JSON.stringify(err));
it returned {}
Note: Mine is 32 bit system.
Is it because there a document limit of 4mb for 32-bit systems?
I'm in a scenario where I can't restrict the size and no.of attributes in the csv file (ie., the code will be handling various kinds of csv files). So how to handle that? I there any modules available?
If you are not having a problem on the parsing the csv into JSON, which presumably you are not, then perhaps just restrict the list size being passed to insert.
As I can see the .csvRows element is an array, so rather than send all of the elements at once, slice it up and batch the elements in the call to insert. It seems likely that the number of elements is the cause of the problem rather than the size. Splitting the array up into a few inserts rather than 1 should help.
Experiment with 500, then 1000 and so on until you find a happy medium.
Sort of coding it:
var batchSize = 500;
for (var i=0; i<jsonObj.csvRows.length; i += batchSize) {
var docs = jsonObj.csvRows.slice(i, i+(batchSize -1));
db.collection.insert( docs, function(err, result) {
// Also don't JSON covert a *string*
console.log(err);
// Whatever
}
}
And doing it in chunks like this.
You can make those data as an array of elements , and then simply use the MongoDB insert function, passing this array to the insert function

fine-uploader unique but ascending ID in filename on submit and cancel

this issue relates to Widen Fine-Uploader ( https://github.com/Widen/fine-uploader )
i got this multipart upload form. no autoupload. i want to upload a couple of images and safe them under an unique name for each image.
eg. you pick 4 images. upload via fine-upload. i already got a gallery id. all images should be saved under a filename using the gallery-id and an unique ascending number. like this:
1234-1.jpg
1234-2.jpg
1234-3.jpg
1234-4.jpg
sounds easy, but there are two problems:
the image-id needs to be ascending without skipping any one. That may happen, if you cancel (remove) a file before upload. so the image-id needs to be set up AFTER selecting all files OR it needs to fill up empty IDs on removing a file.
the order of the images must be strictly adhered to the order you choose files on input. the first image you pick, becomes 1234-1.jpg, the second one 1234-2.jpg ... so i'm not able to set the ID at the imageHandler script after reload. It would grab the first complete image that must not be the first image in order, because i use several simultaneous connections on upload.
I tried something like that:
.on('submitted', function(event, id, name) {
var picId = id+1;
$(this).fineUploader('setParams', {
'currentGid': 1234,
'picId':picId
});
})
or
params: {
fileNum: function() {
return $(this).attr('id');
}
}
or using a fileCount++ but nothing works like i need..
Your application sounds a bit brittle, and it is probably in your best interests to address that.
You'll simply need to maintain a map of your unique ids along with the ids maintained for each file by Fine Uploader. In your "submitted" handler, add a key/value pair to the map. In a "cancel" handler, adjust the items in the map appropriately. In an "upload" handler, call the "setParams" API method. Your parameters will by the gallery ID, the unique ID you've been tracking in your map for that specific file, and be sure to pass the id of the file as your last parameter to the "setParams" call. This lets Fine Uploader know that this parameter is only for that specific file.
Please see the callbacks documentation for more info.
Here's a code example:
var fileIds = [];
$('#myFineuploaderContainer').fineUploader({
//set your options here
})
.on('submitted', function(event, id, name) {
fileIds.push(id);
})
.on('cancel', function(event, id, name) {
var fileIdPosition = $.inArray(id, fileIds);
fileIds.splice(fileIdPosition, 1);
})
.on('upload', function(event, id, name) {
var params = {
currentGid: 1234,
picId: $.inArray(id, fileIds)
};
$(this).fineUploader('setParams', params, id);
});

webOS/Ares : read JSON from URL, assign to label

I've used the webOS Ares tool to create a relatively simple App. It displays an image and underneath the image are two labels. One is static, and the other label should be updated with new information by tapping the image.
When I tap the image, I wish to obtain a JSON object via a URL (http://jonathanstark.com/card/api/latest). The typcial JSON that is returned looks like this:
{"balance":{"amount":"0","amount_formatted":"$0.00","balance_id":"28087","created_at":"2011-08-09T12:17:02-0700","message":"My balance is $0.00 as of Aug 9th at 3:17pm EDT (America\/New_York)"}}
I want to parse the JSON's "amount_formatted" field and assign the result to the dynamic label (called cardBalance in main-chrome.js). I know that the JSON should return a single object, per the API.
If that goes well, I will create an additional label and convert/assign the "created_at" field to an additional label, but I want to walk before I run.
I'm having some trouble using AJAX to get the JSON, parse the JSON, and assign a string to one of the labels.
After I get this working, I plan to see if I can load this result on the application's load instead of first requiring the user to tap.
So far, this is my code in the main-assistant.js file. jCard is the image.
Code:
function MainAssistant(argFromPusher) {}
MainAssistant.prototype = {
setup: function() {
Ares.setupSceneAssistant(this);
},
cleanup: function() {
Ares.cleanupSceneAssistant(this);
},
giveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
},
jcardImageTap: function(inSender, event) {
//get "amount_formatted" in JSON from http://jonathanstark.com/card/api/latest
//and assign it to the "updatedBalance" label.
// I need to use Ajax.Request here.
Mojo.Log.info("Requesting latest card balance from Jonathan's Card");
var balanceRequest = new Ajax.Request("http://jonathanstark.com/card/api/latest", {
method: 'get',
evalJSON: 'false',
onSuccess: this.balanceRequestSuccess.bind(this),
onFailure: this.balanceRequestFailure.bind(this)
});
//After I can get the balance working, also get "created_at", parse it, and reformat it in the local time prefs.
},
//Test
balanceRequestSuccess: function(balanceResponse) {
//Chrome says that the page is returning X-JSON.
balanceJSON = balanceResponse.headerJSON;
var balanceAmtFromWeb = balanceJSON.getElementsByTagName("amount_formatted");
Mojo.Log.info(balanceAmtFromWeb[0]);
//The label I wish to update is named "updatedBalance" in main-chrome.js
updatedBalance.label = balanceAmtFromWeb[0];
},
balanceRequestFailure: function(balanceResponse) {
Mojo.Log.info("Failed to get the card balance: " + balanceResponse.getAllHeaders());
Mojo.Log.info(balanceResponse.responseText);
Mojo.Controller.errorDialog("Failed to load the latest card balance.");
},
//End test
btnGiveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
}
};
Here is a screenshot of the application running in the Chrome browser:
In the browser, I get some additional errors that weren't present in the Ares log viewer:
XMLHttpRequest cannot load http://jonathanstark.com/card/api/latest. Origin https://ares.palm.com is not allowed by Access-Control-Allow-Origin.
and
Refused to get unsafe header "X-JSON"
Any assistance is appreciated.
Ajax is the right tool for the job. Since webOS comes packaged with the Prototype library, try using it's Ajax.Request function to do the job. To see some examples of it, you can check out the source code to a webOS app I wrote, Plogger, that accesses Blogger on webOS using Ajax calls. In particular, the source for my post-list-assistant is probably the cleanest to look at to get the idea.
Ajax is pretty much the way you want to get data, even if it sometimes feels like overkill, since it's one of the few ways you can get asynchronous behavior in JavaScript. Otherwise you'd end up with code that hangs the interface while waiting on a response from a server (JavaScript is single threaded).

Categories

Resources