Server not responding to url with parameters - node.js

I'm attempting to create a server for now should be able to register users.
However the server doesn't react when attempting to register using /reg.
When I create a new .get it does respond though, so the server itself is working.
What also is unclear to me is how to correctly format the url.
app.post('/reg/:uname/:teamid', function(req, res){
var username = req.params.uname;
var teamidpar = req.params.teamid;
UserSchema.pre('save', function (next) {
this1 = this;
UserModel.find({uname : this1.username}, function(err, docs) {
if (!docs.length) {
//Username already exists
} else {
var loginid = randomstring.generate();
var newUser = User({
uname : username,
teamid : teamidpar,
totalscore : 0,
lastopponement : null,
gamescore : 0,
});
User.save(function (err, User, next) {
if (err) {return console.error(err);}
else
{console.log(timestamp+':'+'User created:'+newUser.uname+':'+newUser.login);}
res.json({login : loginid});
});
}
});
});
});

I don't know why I didn't see this earlier, but you use UserSchema.pre at the beginning, however this is just a definition and will not be immediately executed. Only when you actually do a save on a document will this function be triggered.
Below the correct, edited version.
app.post('/reg/:uname/:teamid', function(req, res) {
var username = req.params.uname;
var teamidpar = req.params.teamid;
// If you are just checking if something exist, then try count
// as that has minimal impact on the server
UserModel.count({uname : username}, function(err, count) {
if (count > 0) {
// Username already exists, but always output something as we
// don't want the client to wait forever
return res.send(500);
}
var loginid = randomstring.generate();
// You'll need a new instance of UserModel to define a new document
var newUser = new UserModel({
uname : username,
teamid : teamidpar,
totalscore : 0,
lastopponement : null,
gamescore : 0,
});
// Save the document by calling the save method on the document
// itself
newUser.save(function (err) {
if (err) {
console.error(err);
// You'll want to output some stuff, otherwise the client keeps on waiting
return res.send(500);
}
console.log(timestamp + ': User created:' + username + ':' + loginid);
res.json({login : loginid});
});
});
});

Related

how to handle synchronous databse query in node.js

I am new to node.js, and I am starting with login and signUp implementation, and I have just found that my database Query of MySQL failed to execute in sequence. So what I do is to find does username match exisiting usernames in database, and invitation codes, if there exist, I will send my JSON file with property true, otherwise false, but I have just found, the json file is sent before the database query is finished, so that even if user name matched, the response property is still set to false. I tried async and sync but I still have trouble understanding and fixing my error, can someone please help me on fix or a better alternative implementation in this case? Thank you!!
Here is my code:
// build up connection to db
const con = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'pwd',
database: 'test'
});
// async function search
async function dbFind(db, dbName, attribute, value) {
let users;
try{
console.log(`11111111111111`)
const users = await db.promise().query(`SELECT EMAIL_ADRESS FROM ${dbName} WHERE ${attribute} = ?`, [value]);
// console.log(`users: ${users}`)
if (users) {
return users;
} else {
return null;
}
} catch (err){
console.log(err)
}
}
// parse the json file from front-end and save it in variable data
app.post('/API/user/registration', function(req,res){
con.connect((err) => {
if(err){
console.log(err);
return;
}
console.log('Connection established');
});
var username = req.body.username;
var password = req.body.password;
var invicode = req.body.invitation_code;
var name = req.body.name;
console.log('reqeust ' + req.body)
// variable initialization
var invitationCodeMatched = false;
var role = 'student';
const uid = uuid.v4();
var verifyToken = uuid.v1()
var flag = true;
// // check if the username have already been registered isRegistered
if (dbFind.sync(con, 'login_Authentication', 'EMAIL_ADRESS', username) != null){
flag = false
} else {
flag = true
}
console.log(`1 ${flag}`)
// check invitation code to see if a user qualify for a TA:
if (dbFind(con, 'invitation_code', 'INVITATION_CODE', invicode) != null){
role = 'TA';
invitationCodeMatched = true
}
console.log(`3 ${invitationCodeMatched}`)
// otherwisr: insert it into te database:
const uLoginAuth = {
USER_ID: uid,
EMAIL_ADRESS: username,
PSWORD:password,
VERIFIED: false,
VERIFYCODE: verifyToken
};
const uInfo = {
USER_ID: uid,
NME: name,
USER_ROLE: role,
EMAIL_ADRESS: username
};
if(flag){
con.query('INSERT INTO login_authentication SET ?', uLoginAuth, (err, res) => {
if(err) throw err;
console.log('Last insert ID:', res.insertId);
});
con.query('INSERT INTO user_info SET ?', uInfo, (err, res) => {
if(err) throw err;
console.log('Last insert ID:', res.insertId);
});
}
con.query('SELECT * FROM user_info', (err,rows) => {
if(err) throw err;
console.log('Data received from Db:');
console.log(rows);
});
con.end((err) => {
// The connection is terminated gracefully
// Ensures all remaining queries are executed
// Then sends a quit packet to the MySQL server.
});
//send json file to the front end
console.log(`2 ${flag}`)
let judge = {
isRegistered: flag,
invitationCodeMatched: invitationCodeMatched
};
res.json(judge);
//If the user has not yet verified:
lib.sendConfirmationEmail(name, username, verifyToken)
});
app.listen(3000)
The output while hearing from request is:
1 false
2 false
and there is no output of 11111111 inside async dbFind function, there is a database match in this scenario, but what it returns is :
{
"isRegistered": false,
"invitationCodeMatched": false
}
which is the default value that is initailized before.

Can't access fields of MongoDB document in Node.Js

I'm using mongoose and express on my nodejs project.
Trying to get the data from here
app.get('/offers/:id', (req, res) =>{
//store the id from the url
var id = req.params.id;
//just a placeholder
var data = {title: "title", description:"description"};
//store the returned object in a variable
var oop = offers.findById(id, function (err, user) {
if(err){
return err;
}else{
title = user.title;
description = user.description;
this.obj = {
title:title,
description:description
}
console.log(obj)
return obj;
}
} );
console.log(oop)
res.render('single', {data:data});
});
so my idea is to grab the post id from the url, find it in the database, then display the title and description in the corresponding place on the ejs template, but for some reason I can't access the returned data, and what I get is a long list of objects that belongs to mongodb, without the presence of "title" or "description"
Try this, your code has couple of issues & also you need use .lean() to get raw Js objects rather than mongoDB documents :
app.get('/offers/:id', (req, res) => {
//store the id from the url
var id = req.params.id;
//just a placeholder
var data = { title: "title", description: "description" };
//store the returned object in a variable
offers.findById(id).lean().exec((err, user) => {
if (err) {
console.log(err);
res.send(err)
} else {
data.title = user.title;
data.description = user.description;
this.obj = {
title: title,
description: description
}
console.log(obj);
res.render('single', { data: data });
// (Or) res.render('single', { data: obj });
}
});
});
I just modified your code and added comments (all starting with "***").
app.get('/offers/:id', (req, res) =>{
//store the id from the url
var id = req.params.id;
//just a placeholder
var data = {title: "title", description:"description"};
//store the returned object in a variables
// var oop = ***no need for this, the data you want will be in the user variable.
offers.findById(id, function (err, user) {
if(err){
return err;
}else{
// ***this needs to be changed to...
// title = user.title;
// description = user.description;
// ***that...
data.title = user.title;
data.description = user.description;
// ***what's that for??
// this.obj = {
// title:title,
// description:description
// }
// ***this needs to be inside mongoose's callback
res.render('single', {data:data});
}
});
});

deleting route for an array in mongodB using node.js

var userSchema=new mongoose.Schema({
username:String,
password:String,
email:String,
tasks:[{
task: String
}]
});
This is my database schema.I want to create a delete route for the task to be removed.Can anyone tell me how to do so. Right now I am able to fetch the task id.
Here is link to my c9 project https://ide.c9.io/akspan12/newprojectworkspace
var express = require('express');
var router = express();
//I will take static values you can give dynamic values by using req.body
router.post('/Delete_User_Task',function(req,res){
var UserSchema = require('/path/to/Schema.js');//your schema model path
var username = 'akshansh123'; //assume it is present in db
//If you want to remove all task of this user and set one task as empty string your query and changes will be like below
var query = {
'username' :username
};
var changes = {
$set:{
'tasks':[{
task:''
}]
}
};
//If you completely want to remove json array tasks from user document than your query and changes will be like below
var query = {
'username' :username
};
var changes = {
$unset:{
'tasks':''
}
};
//If you want to remove particular task suppose say sleeping from user document than your query and changes will be like below
var query = {
'username' :username
};
var changes = {
$pull:{
'tasks':{
'task':'sleeping'
}
}
};
//If you want to remove selected tasks suppose say sleeping,walking,drinking from user document than your query and changes will be like below
var query = {
'username' :username
};
var changes = {
$pull:{
'tasks':{
'task':{
$in:['sleeping','walking','drinking']
}
}
}
};
UserSchema.update(query,changes,function(err,Result){
if(!err){
res.send('Successfully Removed tasks');
}else{
res.send('something went wrong');
console.log(err);
}
})
})
Hope this may solve your issue!!!
app.patch("/todo/:id",function(req,res){
User
.findById(req.user.id, function(err, foundUser) {
if(err){
req.flash("error",err.message);
console.log(err);
return res.redirect("back");
} if(!foundUser) {
req.flash("error","User not found");
return res.redirect("back");
} else {
foundUser.update({$pull: {tasks: {_id: req.params.id}}}, function(err) {
if(err) {
req.flash("error",err.message);
console.log(err);
return res.redirect("back");
} else {
req.flash("success","Task removed");
return res.redirect("/todo");
}
});
}
});
});
This is the delete route I used.

Mongoose: model not saving data passed to it

I'm trying to send an object full of data I scraped to a collection on my server. Problem is, it doesn't save whenever I send it to the backend. I'm sending the information to a collection named events. The content constantly sends back a success! You saved a new item. Everytime I check events, however,
it's empty. Here's my code:
Controller
var CronJob = require('cron').CronJob;
var scrape = require("../models/dataScrape");
//code requesting data...
for(var i = 0; i < titles.length; i++){
data.push({"festival" : titles[i], "date" : dates[i], "url" : links[i]});
}
var _id = "12345";
var body = {"_id" : _id, "events" : data};
var job = new CronJob('0*/1 * * * *', function(req, res){
scrape.eventList.find({}, function (err, count) {
if (!err && count.length == 0) {
var newEvents = new scrap.eventList(body);
newEvents.save(function(err, data){
if(error){
console.log("Error: " + err);
}else{
console.log("success! You saved a new item.");
}
});
}else{
scrape.eventList.update({_id: body._id}, body, function(err){
console.log("update");;
if(err){
console.log(err);
}else{
console.log("success! you updated an item.");
}
});
}
});
}
Model
var mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/BackYardBrewing");
var eventsSchema = mongoose.Schema({
id : {type : String},
events : [{
festival : String,
date : String,
url : String,
}],
})
module.exports = {
eventList : mongoose.model("event", eventsSchema),
}
I've used a very similar format on another model, and it saves data just fine. Any hints?
In the if statement of the save method if(error) should be if(err), error doesn't exist.
According to mongoose, your save method should be..
newEvents.save(function(err){
if(err){
console.log("Error: " + err);
}else{
console.log("success! You saved a new item.");
}
});
Or you can use the create method instead
scrap.eventList.create(newEvents, function(err, doc){
if(err)
{ console.log("Error:" + err);}
else{ console.log("success! You saved a new item.");}
});

Why during $save() it generates a new entry in the mongoDB with a string _id?

MEAN stack newbie here. Probably asking a silly question.
As an exercise, I have been trying to implement a prototype SPA which shows a series of task cards on the screen (kinda like Trello).
For now, each card has 4 fields:
_id: ObjectId
content: String
workflow: String
state: String
I am using MongoDB for the database (entered some test data using Robomongo), I have node.js installed on my machine, as well as Express.js.
My server.js file looks like the following:
var express = require('express'),
cards = require('./routes/cards');
var app = express();
app.configure(function() {
app.use(express.logger('dev'));
app.use(express.bodyParser());
});
app.get('/cards', cards.findAll);
app.get('/cards/:id', cards.findById);
app.post('/cards', cards.addCard);
app.put('/cards/:id', cards.updateCard);
app.listen(3000);
console.log('Listening on port 3000...');
My routes/cards.js on the server side look like the following:
var mongo = require('mongodb');
var Server = mongo.Server,
Db = mongo.Db,
BSON = mongo.BSONPure;
var server = new Server('localhost', 27017, {auto_reconnect: true});
var db = new Db('mindr', server);
db.open(function(err, db) {
if(!err) {
console.log("Connected to 'mindr' database");
db.collection('cards', {strict:true}, function(err, collection) {
if (err) {
console.log("The 'cards' collection doesn't exist.");
}
});
}
});
exports.findById = function(req, res) {
var id = req.params.id;
console.log('Retrieving card: ' + id);
db.collection('cards', function(err, collection) {
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
res.send(item);
});
});
};
exports.findAll = function(req, res) {
db.collection('cards', function(err, collection) {
collection.find().toArray(function(err, items) {
res.send(items);
});
});
};
exports.addCard = function(req, res) {
var newCard = req.body;
console.log('Adding card: ' + JSON.stringify(newCard));
db.collection('cards', function(err, collection) {
collection.insert(newCard, {safe:true}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred'});
} else {
console.log('Success: ' + JSON.stringify(result[0]));
res.send(result[0]);
}
});
});
}
exports.updateCard = function(req, res) {
var id = req.params.id;
var card = req.body;
console.log('Updating card: ' + id);
console.log(JSON.stringify(card));
db.collection('cards', function(err, collection) {
collection.update({'_id':new BSON.ObjectID(id)}, card, {safe:true}, function(err, result) {
if (err) {
console.log('Error updating card: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + result + ' document(s) updated');
res.send(card);
}
});
});
}
exports.deleteCard = function(req, res) {
var id = req.params.id;
console.log('Deleting card: ' + id);
db.collection('cards', function(err, collection) {
collection.remove({'_id':new BSON.ObjectID(id)}, {safe:true}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred - ' + err});
} else {
console.log('' + result + ' document(s) deleted');
res.send(req.body);
}
});
});
}
When I get the cards from the DB in my AngularJS controller, everything goes fine. All the cards are correctly displayed on the screen. This is the code that gets the cards:
var mindrApp = angular.module('mindrApp', ['ngResource'])
mindrApp.controller('WorkflowController', function ($scope, $resource) {
var CardService = $resource("http://localhost:3000/cards/:cardId", {cardId:"#id"});
$scope.cards = CardService.query();
});
On each card there are some buttons that can be used to change the state of the card to the next state available in the workflow (as defined by the current state available actions).
When the button is clicked, the card id and the next state are passed to a function in the controller:
<div class="btn-group btn-group-xs">
<button type="button" class="btn btn-default"
ng-repeat="currentAction in currentState.actions | filter:{default:true}"
ng-click="processCard(currentCard._id, currentAction.next)">
{{currentAction.name}}
</button>
</div>
And this is the processCard function in the controller:
$scope.processCard = function(id, nextState) {
var currentCard = CardService.get({cardId: id}, function(){
currentCard.state = nextState;
currentCard.$save();
});
};
What's happening is that when I click the button, instead of changing the state of the current card, a new card is created with an id field of type String. This is the output of the server:
Retrieving card: 52910f2a26f1db6a13915d9f
GET /cards/52910f2a26f1db6a13915d9f 200 1ms - 152b
Adding card: {"_id":"52910f2a26f1db6a13915d9f","content":"this is some content for this really cool card","workflow":"simple","state":"completed"}
Success: {"_id":"52910f2a26f1db6a13915d9f","content":"this is some content for this really cool card","workflow":"simple","state":"completed"}
POST /cards 200 1ms - 150b
Any idea why this is happening? Why is it calling the addCard function on the server instead of calling the updateCard function?
The $save() action of a $resource object use POST as default request type (Read more here). So in your case, a POST request to the route /cards/:id was called, so as a result, a new card was created.
Either create a new route entry to handle POST update request in server.js
app.post('/cards/:id', cards.updateCard);
Or add another action that use PUT to your CardService and call it when you want to update your card
var CardService = $resource("http://localhost:3000/cards/:cardId", {cardId:"#id"},
{ update: { method: 'PUT' } }
);
// update the card
...
currentCard.$update();
Ok, so I figured it out. The two problems I were having were:
1) instead of updating the existing item in the database, it was creating a new one with the same ID but in string format instead of using the ObjectId format.
2) any time I called $update, it would not append the ID to the path, but always PUT to /cards.
So here are the solutions to each of the problems.
1) This is really a hack that assumes that ALL id are in ObjectId format. I don't like this solution but for now it works and I am sticking to it. All I had to do was to add the line that converts the card._id back to ObjectId format to the updateCard function inside the cards.js file on the server side.
exports.updateCard = function(req, res) {
var id = req.params.id;
var card = req.body;
console.log('Updating card: ' + id);
console.log(JSON.stringify(card));
card._id = new BSON.ObjectID.createFromHexString(card._id); // HACK!
db.collection('cards', function(err, collection) {
collection.update({'_id':new BSON.ObjectID(id)}, card, {safe:true}, function(err, result) {
if (err) {
console.log('Error updating card: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + result + ' document(s) updated');
res.send(card);
}
});
});
}
2) This was a two part fix. First, I had to modify the services.js file to explicitly say that I want to use update via PUT:
var mindrServices = angular.module('mindrServices', ['ngResource']);
mindrServices.factory("Card", ["$resource",
function($resource) {
return $resource("http://localhost:3000/cards/:cardId", {cardId:"#id"},
{
query: {method: "GET", isArray:true},
update: {method: "PUT"}
}
);
}]);
Next, I was under the assumption that simply calling currentCard.$update() would grab the ID from the calling instance, instead I have to explicitly pass in the ID as follows:
var mindrControllers = angular.module('mindrControllers', []);
mindrControllers.controller('CardsController', ["$scope", "Card",
function ($scope, Card) {
$scope.cards = Card.query();
console.log("cards populated correctly...");
$scope.processCard = function(currentCard, currentAction) {
console.log("processCard: card[" + currentCard._id + "] needs to be moved to [" + currentAction.next + "] state... ");
currentCard.state = currentAction.next;
currentCard.$update({cardId: currentCard._id}); // passing the ID explicitly
}
This is the output I get on the server side:
Updating card: 52910eb526f1db6a13915d9c
{"_id":"52910eb526f1db6a13915d9c","content":"this is some content for this really cool card","workflow":"simple","state":"backlog"}
1 document(s) updated
PUT /cards/52910eb526f1db6a13915d9c 200 4ms - 111b

Resources