nodejs-javascript update object - javascript

I'm new to nodejs and trying to write a function to update and object on mongodb.
Here is my fundtion that is under routs/rates.js. Briefly, the function is called whenever a button/link called "like" is clicked and it should update the total number of like this item has recieved. Item is an object in my mongodb.
router.put('/update_likes', function (req, res) {
var sessionId = req.sessionID;
var queryId = req.body.queryId;
var item = req.body.item;
var itemId= req.body.itemId;
var commentsNum= req.body.commentsNum;
var category= req.body.category;
var find_condition = {
'item': item,
'sessionId': req.sessionID,
'category': category,
'commentsNum': commentsNum
};
var update_callback = function (err, item_obj) {
if (err)
return console.log('An error occurred: ', err);
var update = {
$inc: { 'totalLikes': 1 },
$push: {
'likes': {
'itemId': itemID,
'sequence': item_obj.totalLikes + 1
}
}
};
Query.update(find_condition, update, function (err) {
if (err)
return console.log('[UPDATE] ', err);
});
}
Query.findOne(find_condition, update_callback);
res.sendStatus(200);});
Using the function above, gives me an error that totalLikes is undefined in line 15. What I understant is that I cannot use item_obj inside var update = {}, but I actually don't know how to solve this issue in another way.
Any hints? or suggested enhancements to the code?

Related

nodejs mongoDB findOneAndUpdate(); returns true even after database is updated

i am working on an Ionic-1 + nodejs + angular application. My mongoDb findOneAndUpdate() function returns true on each call even the first call updates database.
nodejs:
app.post('/booking', function (req, res) {
var collection = req.db.get('restaurant');
var id = req.body.id;
var status = req.body.status;
collection.findOneAndUpdate({status: status, id: id},{$set:{status:"booked"}}, function (e, doc) {
console.log(id, status);
if (e) {
console.log(e);
}
else if(!doc) {
res.send(false);
}
else {
res.send(true);
}
});
});
controller.js
$scope.bookMe = function(id){
var Obj = {status: "yes", id: id};
myService.booking(Obj).success(function(res){
console.log(Obj, "Checking status")
console.log(res);
if (res == true) {
var alertPopup = $ionicPopup.alert({
title: 'Booking Confirm',
template: 'Thanks For Booking'
});
}
else{
var alertPopup = $ionicPopup.alert({
title: 'Error',
template: ' Not available'
});
}
})
};
where i am doing wrong. my DB gets updated but it returns true always on next call.
The documentation about findOneAndUpdate says :
Finds a matching document, updates it according to the update arg, passing any options, and returns the found document (if any) to the callback. The query executes immediately if callback is passed.
So it's regular behavior you got a doc.
Note:
Since you are checking availability status="yes", Better hard code, instead of getting it from request query/data.
Change the response according to your requirement res.send(true)/ res.send(false).
Following code will work
app.post('/booking', function (req, res) {
var collection = req.db.get('restaurant');
collection.findOneAndUpdate({
status: "yes",
_id: req.body.id
}, {
$set: {
status: "booked"
}
}, function (err, result) {
//Error handling
if (err) {
return res.status(500).send('Something broke!');
}
//Send response based on the required
if (result.hasOwnProperty("value") &&
result.value !== null) {
res.send(true);
} else {
res.send(false);
}
});
});

Method name is not a function

I have problem in calling the method in my module.
There is an errorTypeError: usr.User.getAddress is not a function
I don't know how to fix this I think I have problem in my module code. I want to get the address or the result.
in my main.js
var mysql = require('mysql');
var usr = require('./user');
var useraddress = usr.User.getAddress (id,pool); //this is how I access the method
in my user.js
exports.User = function () {
return {
getAddress: function (userid, pool){
pool.getConnection(function (err, connection) {
var options = {
sql: " select address from user where id = ?
};
var querypos = connection.query(options, [userid], function (err, results) {
if (err) throw err;
});
});
}
};
};
You are exporting User as a factory function which returns an object with getAddress method on it. So you need to invoke (instantiate) User first:
var useraddress = usr.User().getAddress(id, pool);
Another important problem. connection.query request is asynchronous, which means that assigning getAddress result to var useraddress doesn't make sense. Instead you need to either pass callback to getAddress or use Promise pattern (check this post for great deal of details on the topic: How do I return the response from an asynchronous call?).
In your case I think something like this would be a simplest working approach:
exports.User = function () {
return {
getAddress: function (userid, pool){
pool.getConnection(function (err, connection) {
var options = {
sql: "select address from user where id = ?"
};
var querypos = connection.query(options, [userid], function (err, results, callback, errCallback) {
if (err) {
errCallback(err);
}
callback(results);
});
});
}
};
};
and usage:
usr.User().getAddress(id, pool, function(result) {
console.log('Loaded', result);
});
This is because usr.User does not have .getAddress property on it.
To use .getAddress as a property, you need to export User as an object instead.
exports.User = {
getAddress: function (userid, pool){
pool.getConnection(function (err, connection) {
var options = {
sql: " select address from user where id = ?
};
var querypos = connection.query(options, [userid], function (err, results) {
if (err) throw err;
});
});
}
};
};
Now it does.

Use counter collection in node.js to increment ID field

I wanted to set up an auto incrementing ID on one of my collections (_id is too long). To do this I created a 'counters' collection as suggested in a number of posts including Mongos official site (below):
var mongoose = require('mongoose');
module.exports = mongoose.model('Counter', {
_id: String,
sequence_value: Number
});
I then inserted one counter with a seq value. Below is a function which is called when creating a new Item. The Logic to add the new item works and the query to get the counter value works to the extent that console.log(data.sequence_value); returns the sequence_value.
But I cannot then apply the sequence_value to the item creation logic by doing something like the following:
module.exports.newitem = function(req, res){
var nextId = Counter.findByIdAndUpdate(
{_id: 'productid'},
{ $inc: { incr: 1 } },
function (err, data) {
if(err){
console.log(err.stack || err.message)
} else{
console.log("successful")
}
console.log(data.sequence_value);
return data.sequence_value
});
var item = new Item();
item.itemId = nextId;
// Save the item that has been sent.
item.save();
// If adding the user is successful. Send back the user.
res.json(req.body);
};
The current disjointed version of the logic is below:
module.exports.newitem = function(req, res){
Counter.findByIdAndUpdate(
{_id: 'productid'},
{ $inc: { incr: 1 } },
function (err, data) {
if(err){
console.log(err.stack || err.message)
} else{
console.log("successful")
}
console.log(data.sequence_value);
});
var item = new Item();
item.itemId = "2000";
// Save the item that has been sent.
item.save();
// If adding the user is successful. Send back the user.
res.json(req.body);
};
Hopefully the above makes sense. Any help is very appreciated.
findByIdAndUpdate is an an asynchronous function. You should put your logic depending on its callback inside the callback itself, like so:
var nextId = Counter.findByIdAndUpdate(
{_id: 'productid'},
{ $inc: { incr: 1 } },
function (err, data) {
if(err){
console.log(err.stack || err.message)
} else{
console.log("successful")
}
console.log(data.sequence_value);
var item = new Item();
item.itemId = data.sequence_value;
// Save the item that has been sent.
item.save(); // arguably, your response would come in the .save() callback, if you care about whether that was successful or not.
// If adding the user is successful. Send back the user.
res.json(req.body);
});
};
Thought I would put what I ended up with using Paul's answer.
module.exports.newitem = function(req, res){
Counter.findByIdAndUpdate(
{_id: 'productid'},
{ $inc: { sequence_value: 1 } },
{ "upsert": true },
function (err, data) {
if(err){
console.log(err.stack || err.message)
} else{
var item = new Item();
item.itemId = data.sequence_value;
...
// Save the item that has been sent.
item.save();
// If adding the user is successful. Send back the user.
res.json(req.body);
console.log("successful")
}
});
};

ExpressJS re-query database after adding record to database

I'm new to expressJS and i'm wondering what is the best way to requery the database (mongo in my case) to get all the records after one is added.
exports.get = function (db) {
return function (req, res) {
var collection = db.get('notes');
collection.find({}, {}, function (e, docs) {
res.send(docs);
});
};
};
exports.create = function (db) {
return function (req, res) {
var title = req.body.title;
var note = req.body.note;
var collection = db.get('notes');
// Insert/update the note
collection.insert(
{
"title": title,
"note": note
},
function (err, doc) {
// If it failed, return error
if (err) {
res.send("There was a problem adding the information to the database. Error: "+err);
} else {
//res.redirect('/');
//res.json(db.get('notes'));
// WHAT IS THE BEST THING TO DO HERE TO GET ALL THE RECORDS INCLUDING THE ONE I'VE JUST ADDED?
exports.get(db);
}
}
);
}
};
I would replace
exports.get(db);
for
collection.find({}, {}, function (e, docs) {
res.send(docs);
});
The reason is that you are invoking this in the callback, AFTER the record has been inserted
Your exports.get function return a function, a kind of middleware I see.
Repplace
exports.get(db);
by
exports.get(db)();

Mongoose / JavaScript - Saving error - undefined object

I am trying to save a match between 2 teams, I am passing the 2 teams through a drop down list.
When I use util.log to output the homeTeam to the console when INSIDE the Team.findByKey method it works successfully and here is the output:
3 Mar 19:52:33 - { name: 'Liverpool',
_id: 51312074bb176ba624000007,
__v: 0,
key: 1362174068837 }
But as soon as I try to do this outside of this method I get the following output which means that when I try to save this as a match, the hometeam appears as just undefined rather than the id of the hometeam:
3 Mar 19:54:09 - [object Object]
My problem is that I am eventually wanting to save both a home team and an away team to the same match in one save. The code for saving a match works when inside the Team.findByKey method which is as follows:
app.get('/save/matchTest', function(req, res) {
var key = 1362174006191; // Man Utd 51312036bb176ba624000001
Team.findByKey(key, function(err, team) {
util.log(team);
if(err) {
util.log("Error occured");
}
if(!team) {
util.log("The team does not exist");
}
var match = new Match({
hometeam: team._id
});
match.save(function(err) {
if(err) {
util.log('Error while saving Match: ' + util.inspect(err));
res.send("An error occured whilst saving the match");
} else {
res.send("Saved the match");
}
});
});
});
But what I want to do is to be able to save a match with the following
var match = new Match({
hometeam: homeTeam._id,
awayteam: awayTeam._id
});
Does anyone have any ideas?
Here is the relevant code:
JavaScript
submitMatch = function(){
var homeId = $("#homeTeamList").val();
var awayId = $("#awayTeamList").val();
//alert("home: " + homeId + " away: " + awayId);
// Frontend sends the data
var matchForm = {
homeKey : $('#homeTeamList').val(),
awayKey : $('#awayTeamList').val()
};
// Basic validation
$.post('/save/match', {'matchForm' : matchForm}, function(response) {
console.log(response);
});
};
/save/match
app.post('/save/match', function(req, res) {
util.log('Serving request for url [GET] ' + req.route.path);
// Output to console to test what is being passed to Save Match
// Entire body passed to console
//console.log('body: ', req.body);
// Entire matchForm from body
//console.log('matchForm: ', req.body.matchForm);
// Home Key from matchForm
//console.log('homeKey: ', req.body.matchForm.homeKey);
// Away Key from matchForm
//console.log('awayKey: ', req.body.matchForm.awayKey);
// Get data from match Form
var matchForm = req.body.matchForm;
// Check if a match with 2 teams has been submitted
if(matchForm.homeKey === '' || matchForm.homeKey === undefined ||
matchForm.awayKey === '' || matchForm.awayKey === undefined){
// Not a valid match
util.log('Not valid match');
} else {
var homeId = matchForm.homeKey;
var awayId = matchForm.awayKey;
var homeTeam = Team.findByKey(homeId, function(err, homeTeam) {
util.log(homeTeam);
if(err) {
util.log("Error occured");
}
if(!homeTeam) {
util.log("The home team does not exist");
}
});
var match = new Match({
hometeam: homeTeam._id
});
//util.log(match);
}
});
In /save/match you're using the value of homeTeam in the Match constructor before it's been set by the callback. You need to create the Match inside both the home and away team findByKey callbacks like this:
Team.findByKey(homeId, function(err, homeTeam) {
util.log(homeTeam);
if(err) {
return util.log("Error occured");
}
if(!homeTeam) {
return util.log("The home team does not exist");
}
Team.findByKey(awayId, function(err, awayTeam) {
util.log(awayTeam);
if(err) {
return util.log("Error occured");
}
if(!awayTeam) {
return util.log("The away team does not exist");
}
var match = new Match({
hometeam: homeTeam._id,
awayteam: awayTeam._id
});
});
});
To look up the home and away teams in parallel while still keeping your code organized, you'll want to look at using a flow control library like async.

Categories

Resources