Can you get node js to send an array not a string - javascript

I want the code to return a 2d array of the results.
E.g.
clothes = [[1,"name","desc"],[2,"name2","desc2"]]
can you make res send a list or do you have to make a list once you have returned it?
app.get('/post', (req, res) => {
con.connect(function(err) {
if (err) throw err;
var query = "SELECT * FROM products"
con.query(query, function (err, results, fields) {
if (err) throw err;
var clothes = [];
Object.keys(results).forEach(function(key) {
let r = []
var row = results[key];
r.push(row.ID);
r.push(row.name);
r.push(row.link);
r.push(row.imageLink);
r.push(row.type);
r.push(row.colour);
r.push(row.price);
r.push(row.brand);
clothes.push(r);
});
res.send(clothes);
});
});
});
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
clothes = this.response;
document.getElementById("demo").innerHTML = clothes;
};
xhttp.open("GET", "http://localhost:3000/post", true);
xhttp.send();

Yes of course.
Check out the official NodeJS documentation
Example:
app.get('/post', (req, res) => {
con.connect(function(err) {
if (err) throw err;
var query = "SELECT * FROM products"
con.query(query, function (err, results, fields) {
if (err) throw err;
var clothes = [];
...
// Better set the header so the client knows what to expect; safari requires this
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(clothes));
});
});
});
You seem to be using the expresjs framework
Here you have a convenience method to do the above:
...
con.query(query, function (err, results, fields) {
if (err) throw err;
var clothes = [];
res.json(clothes);
});
...
Read the response on the client side
This is a good answer on how to do this.
In short: It is recommended to use the new fetch() method on client side.
fetch("http://localhost:3000/post")
.then(function(response) {
return response.json();
})
.then(function(clothes) {
document.getElementById("demo").innerHTML = clothes;
});

Related

Connection to Mongodb through Node.js

Hii Everyone
In my code, There is an API that works fine.
And I'm trying to connect to MongoDB from Node for the sake of inserting the data from the API.
As you can see, I get this error -
"message": "Uncaught SyntaxError: Unexpected identifier",
it looks like there is a problem with MongoClient.
I looked at the answers on this site about those topics and no one solves my problem.
Thanks for any help!
let http = require('http');
let weatherKey = process.env.weatherKey;
// console.log(weatherKey);
function getData(cb) {
http.get(`http://api.openweathermap.org/data/2.5/weather?q=israel&appid=${weatherKey}`, res => {
let data = ""
res.on('data', string => {
data += string
})
res.on('end', () => {
let obj = JSON.parse(data)
cb(obj);
})
}).on("error", error => {
cb(error);
})
}
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://127.0.0.1:27017/";
function connectToMongo(data)
MongoClient.connect(url, function (err, db) {
if (err) throw err;
var dbo = db.db("weather-db");
dbo.collection("node").insertOne(data, err => {
if (err) throw err;
console.log("documents inserted");
db.close();
});
});
getData(connectToMongo);
Your function is missing { after (data)
You were missing {} in your code.
let http = require('http');
let weatherKey = process.env.weatherKey;
function getData(cb) {
http.get(`http://api.openweathermap.org/data/2.5/weather?q=israel&appid=${weatherKey}`, res => {
let data = ""
res.on('data', string => {
data += string
})
res.on('end', () => {
let obj = JSON.parse(data)
cb(obj);
})
}).on("error", error => {
cb(error);
})
}
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://127.0.0.1:27017/";
function connectToMongo(data){
MongoClient.connect(url, function (err, db) {
if (err) throw err;
var dbo = db.db("weather-db");
dbo.collection("node").insertOne(data, err => {
if (err) throw err;
console.log("documents inserted");
db.close();
});
});
}
getData(connectToMongo);

why mongodb in node express cannot set result to outside variable

So this question might be a javascript concept question. but I cannot figure out why
I retrieve data from mongodb however, I cannot define _res variable to become the result.
console.log(_res) will return undefined.
Does anyone know why? and how to make it work as it should be?
app.route('/').get(function(req,res){
let _res;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("vm");
var query = {};
dbo.collection("vm").find(query).toArray( function(err, result) {
if (err) throw err;
var vmData = JSON.stringify (result)
_res = vmData
db.close();
res.render('index.ejs', {
vmData: vmData
});
});
});
console.log(_res)
});
Mongodb query is an asynchronous operation. The console statement is executed before the query has been processed.
You define _res outside which is undefined outside, so the same value is consoled outside.
app.route('/').get(function(req,res){
let _res;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("vm");
var query = {};
dbo.collection("vm")
.find(query)
.toArray((err, result){
if (err) throw err;
var vmData = JSON.stringify (result)
_res = vmData
db.close();
console.log('Inside', _res) // <---Should give you correct result
res.render('index.ejs', {
vmData: vmData
});
});
});
console.log('Outside', _res);
});
The code is being executed asynchronously due to which when the console.log is executed the _res is undefined.
Try to execute your logic when the asyn methods are being executed.
app.route('/').get(function(req,res){
let _res;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("vm");
var query = {};
dbo.collection("vm").find(query).toArray( function(err, result) {
if (err) throw err;
var vmData = JSON.stringify (result)
_res = vmData;
console.log(_res);
db.close();
res.render('index.ejs', {
vmData: vmData
});
});
});
});

How to turn a query result into a js variable (Javascript)

I've been searching for this for a day now and I'm basically hopeless.
All I want to do is export the query result as a string (so dataString basically) so I can import as a string in my external .js file.
module.exports.getKlanten = function(req, res){
console.log("zoekt naar klanten");
pool.connect(function(err, client, done){
if(err){
return console.error('error fetching client from pool', err);
}
client.query("select * from abc.relations limit 5", function(err,result){
done();
if(err){
return console.error('error running query', err);
}
var dataString = JSON.stringify(result.rows);
var count = Object.keys(result.rows).length;
var klanten = result.rows;
res
.status(200)
.render("index", {dataString: dataString, klant: klanten, count: count});
console.log("done");
})
});
}
And what would I have to do in the js file to import the string then? It looks so easy yet I can't seem to get it right.
It would be something like this
module.exports.getKlanten = function(req, res){
console.log("zoekt naar klanten");
return "Hello world"; }
and then in your external .js file, you can import it like this
const myModule = require('./JSFile');
and use it like this
console.log(myModule.getKlanten());
Also, use a return statement so that you have a string in your variable.
I am assuming that you need to use the same function externally somewhere else and also for http handler so split it into three files.
//getKlanten.js
module.exports.getKlanten = function(){
return new Promise(function (resolve, reject) {
pool.connect(function(err, client, done){//make sure pool is avialble here
if(err){
console.error('error fetching client from pool', err);
reject(err);
}
client.query("select * from abc.relations limit 5", function(err,result){
if(err){
console.error('error running query', err);
reject(error);
}
var dataString = JSON.stringify(result.rows);
var count = Object.keys(result.rows).length;
var klanten = result.rows;
var data = {dataString: dataString, klant: klanten, count: count}
resolve(data);
})
});
})
}
//in external.JS
var getKlanten = require('getKlanten');
getKlanten().then(function(object) {
console.log(object);
}, function(err){
console.log(err);
})
//in http handler file
var getKlanten = require('getKlanten');
module.exports = function(req,res) {
getKlanten().then(function(data) {
res
.status(200)
.render("index", data);
});
}

Nodejs Mongoose Saving model undefined is not a function

I work with Nodejs Express routes and Mongoose to persist data.
I did the core routes CRUD operations with no problem. However, when I try to perform some operations on one of the fields of the Model and then try to save the Model with model.save it says about .save() method: "undefined is not a function"
So, here's the code.
The snippet number (1) works just fine:
router.put('/:myId', function (req, res, next) {
var ourUpdateData = req.body;
Model.findOne({myId: req.params.myId.toString()}, function (err, foundModel) {
if (err) throw err;
if (ourUpdateData.fieldA) foundModel.fieldA = ourUpdateData.fieldA;
if (ourUpdateData.fieldB) foundModel.fieldB = ourUpdateData.fieldB;
if (ourUpdateData.fieldC) foundModel.fieldC = ourUpdateData.fieldC;
if (ourUpdateData.fieldD) foundModel.fieldD = ourUpdateData.fieldD;
if (typeof ourUpdateData.fieldArray === "object") ourUpdateData.fieldArray = ourUpdateData.fieldArray;
foundModel.save(function (err, updatedModel) {
if (err) throw err;
res.send(updatedmodel);
});
});
});
So the Model has 6 fields: fieldA,..B,..C,..D, myId to identify as index and one field is Array of some values fieldArray. The example above saves the Model, works fine.
However if I now try to do something with array field fieldArray and then save the Model it throws me "undefined is not a function" when I use model.save() .
So the snippet (2) is the code that produces this error:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.find({myId: myId}, function (err, model) {
if (err) throw err;
var fieldArray = model.fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model.fieldArray = newFieldArray;
model.save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
So that thing above throws "undefined is not a function" on using model.save(.. )
I also tried second variant of the snippet (2), let's call it snippet (3), incorporating the .exec() Also doesn't work, throws the same "undefined is not a function" on model.save(.. )
So the snippet (3) is this:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.find({myId: myId}).exec(function (err, model) {
if (err) throw err;
var fieldArray = model.fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model.fieldArray = newFieldArray;
model.save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
I'll be greatful for any inputs and suggestions!
Ansering to the attempt of Willson:
Yeah, I know when I call model.find(.. it gives array, if I call model.findOne(.. it gives one object json
I tried to simplify my example and in my version I actualy did use the:
"model[0].fieldArray = newFieldArray" to get the thing from Array fist (the array itself) and then assign to the new value.
The problem still persists, it gives me on model.save(.. "undefined is not a function " )
The current code is:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.find({myId: myId}).exec(function (err, model) {
if (err) throw err;
var fieldArray = model[0].fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model[0].fieldArray = newFieldArray;
model.save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
This snippet (4) above gives on model.save(.. "undefined is not a function"
When you use in Mongoose the find method, it will return an array since it could discover one or many documents, so in your example you are querying to one specific element by its id, you should grab the first element on the returned array:
Model.find({myId: myId}).exec(function (err, documents) {
var model = documents[0];
if (err) throw err;
var fieldArray = model[0].fieldArray;
Here is an example:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost:27017/java-jedi');
var HackerSchema = new Schema({
name: String,
languages: [String]
});
var Hacker = mongoose.model('Hacker', HackerSchema);
// instantiating the model.
var oneHacker = new Hacker();
oneHacker.name = 'Richard Stallman';
oneHacker.save(function(err) {
if (err) throw err;
// finding the document intentionally for this example
Hacker.find({_id: oneHacker._id}, function(err, hackers) {
var hacker = hackers[0];
// modifying the document and updating it.
hacker.languages.push('Lisp');
hacker.save(function(err) {
if (err) throw err;
console.log(hacker);
});
});
});
OK guys!
I want to thank Wilson Balderrama, because he basically pointed to the right direction.
The code works! But let me clearify a bit.
Hacker.find({_id: oneHacker._id}, function(err, hackers) {
var hacker = hackers[0];
// modifying the document and updating it.
hacker.languages.push('Lisp');
hacker.save(function(err) {
if (err) throw err;
console.log(hacker);
});
});
So basically since the Model.find(.. returns an array
when we save we have to grab the thing from array before saving.
So corrected and final working version of my example will be:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.find({myId: myId}).exec(function (err, model) {
if (err) throw err;
var fieldArray = model[0].fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model[0].fieldArray = newFieldArray;
model[0].save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
Or we can use just Model.findOne(.. to avoid confusing ourselves with this arry return
In this case we grab directly:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.findOne({myId: myId}).exec(function (err, model) {
if (err) throw err;
var fieldArray = model.fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model.fieldArray = newFieldArray;
model.save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
So in second case model[0].save(... becomes model.save(... direct grabbing and saving.
Thank you Wilson Balderrama again!!

JS - Express - Mongoose execute all mongoose's promises before send a response

Im doing a forum api, where a forum has many threads, thread has many posts and post could have many post.
The relations are done like this:
var PostSchema = new Schema({
text: String,
authorId: String,
slug: Number,
posts: [{ type: Schema.Types.ObjectId, ref: 'Post'}],
created: { type: Date, default: Date.now }
});
The parent model has a list of ids of son model.
I made my controller like this:
var util = require('util'),
mongoose = require('mongoose'),
Forum = mongoose.model('Forum'),
Thread = mongoose.model('Thread'),
Post = mongoose.model('Post'),
async = require('async');
exports.show = function(req, res){
var forums;
var getThreads = function(forum) {
return forum.populate('threads', function(err, _forum){
if(err) throw new Error(err);
forum.threads = _forum.threads;
forum.threads.forEach(getPosts);
return callback(err);
});
};
var getPosts = function(thread) {
return thread.populate('posts', function(err, _thread){
if(err) throw new Error(err);
thread.posts = _thread.posts;
thread.posts.forEach(getComments);
return callback(err);
});
};
var getComments = function(post) {
return post.populate('posts', function(err, _post){
if(err) throw new Error(err);
post.posts = _post.posts;
post.posts.forEach(getComments);
return callback(err);
});
};
async.parallel([
function(callback) {
return Forum.find({ ownerId: req.params.owner_id }).exec(function(err, _forums) {
if(err) throw new Error(err);
forums = _forums;
forums.forEach(getThreads);
return callback(err);
});
}
], function(err){
res.json(forums);
}
);
};
I need to made the complete forum object, then use this on the response, as posts has posts i cannot just do a nested populate.
I tried to use the async lib, but it execute the callback function before the promises.
How can i build the complete forum object?
You need to properly handle your tree structure in an asynchronous way. Try this approach:
(I haven't tested, but hope it works)
// ...
var Forum = mongoose.model('Forum');
exports.show = function(req, res){
//Get the owner's forums
Forum.find({ ownerId: req.params.owner_id }).exec(function(err, forums) {
if(err) throw new Error(err);
if(!forums.length) return response.json(forums); //Send an empty array if no forums where found
//Build forums one by one
var forum = forums.shift();
buildForum(forum, function () {
forum = forums.shift();
if (forum) {
buildForum(forum, this);
} else {
//All forums were built.
res.json(forums);
};
});
});
var buildForum = function (forum, onSuccess) {
forum.populate('threads', function(err, forum){
if(err) throw new Error(err);
if(!forum.threads.length) return onSuccess();
//Build threads one by one
var threads = forum.threads;
var thread = threads.shift();
buildThread(thread, function () {
thread = threads.shift();
if (thread) {
buildThread(thread, this);
} else {
//All threads were built.
onSuccess();
};
});
});
};
var buildThread = function (thread, onSuccess) {
thread.populate('posts', function(err, thread){
if(err) throw new Error(err);
if(!thread.posts.length) return onSuccess();
//Build posts one by one
var posts = thread.posts;
var post = posts.shift();
buildPost(post, function () {
post = posts.shift();
if (post) {
buildPost(post, this);
} else {
//All posts were built.
onSuccess();
};
});
});
};
var buildPost = function (post, onSuccess) {
post.populate('posts', function(err, post){
if(err) throw new Error(err);
if(!post.posts.length) return onSuccess();
//Build comments one by one
var posts = post.posts;
var _post = posts.shift();
buildPost(_post, function () {
_post = posts.shift();
if (_post) {
buildPost(_post, this);
} else {
//All comments were built.
onSuccess();
};
});
});
};
};
This is my solution, just a minor fixs in the #Danypype solution.
exports.show = function(req, res){
//Get the owner's forums
Forum.find({ ownerId: req.params.owner_id }).exec(function(err, forums) {
if(err) throw new Error(err);
if(!forums.length) return response.json(forums); //Send an empty array if no forums where found
//Build forums one by one
var forum = forums.shift();
var responseForums = [forum];
buildForum(forum, function () {
forum = forums.shift();
if (forum) {
responseForums.push(forum);
buildForum(forum, arguments.callee);
} else {
//All forums were built.
res.json(responseForums);
};
});
});
var buildForum = function (forum, onSuccess) {
forum.populate('threads', function(err, forum){
if(err) throw new Error(err);
if(!forum.threads.length) return onSuccess();
if(forum.length == 1) return onSuccess();
var thread = forum.threads.shift();
var responseThreads = [thread];
buildThread(thread, function () {
thread = forum.threads.shift();
if (thread) {
responseThreads.push(thread)
buildThread(thread, arguments.callee);
} else {
//All threads were built.
forum.threads = responseThreads;
onSuccess();
};
});
});
};
var buildThread = function (thread, onSuccess) {
thread.populate('posts', function(err, thread){
if(err) throw new Error(err);
if(!thread.posts.length) return onSuccess();
var post = thread.posts.shift();
var responsePosts = [post]
buildPost(post, function () {
post = thread.posts.shift();
if (post) {
responsePosts.push(post);
buildPost(post, arguments.callee);
} else {
//All posts were built.
thread.posts = responsePosts;
onSuccess();
};
});
});
};
var buildPost = function (post, onSuccess) {
post.populate('posts', function(err, post){
if(err) throw new Error(err);
if(!post.posts.length) return onSuccess();
//Build comments one by one
var _post = post.posts.shift();
var response_posts = [_post];
buildPost(_post, function () {
_post = post.posts.shift();
if (_post) {
response_posts.push(_post);
buildPost(_post, arguments.callee);
} else {
//All comments were built.
post.posts = response_posts;
onSuccess();
};
});
});
};
};

Categories

Resources