What am I doing wrong on my update function on nodejs/mongodb? - javascript

Hi I am currently new to nodejs and mongodb what I want to do is make a function to update my win,lose,draw record from my userschema.
My Schema:
UserSchema = new mongoose.Schema({
username:'string',
password:'string',
email:'string',
//Change Made
win:{ type: Number, default: 0 },
lose:{ type: Number, default: 0 },
draw:{ type: Number, default: 0 }
});
var db = mongoose.createConnection(app.get('MONGODB_CONN')),
User = db.model('users', UserSchema);
My Function for updating:
app.post('/user/updateScores',function(req, res){
try{
var query = req.body.username;
User.findOneAndUpdate(query, { win : req.body.win, lose : req.body.lose, draw : req.body.draw }, function (err,user){
if (err) res.json(err) ;
req.session.loggedIn = true;
res.redirect('/user/' + user.username);
});
}
catch(e){
console.log(e)
}
});
The problem is when I try updating, it updates the current data BUT goes to a blank page and throws an exception saying:
ReferenceError: win is not defined
at eval (eval at <anonymous> (C:\Users\ryan-utb\Desktop\RockScissorsPaper\node_modules\underscore\underscore.js:1176:16), <anonymous>:5:9)
at template (C:\Users\ryan-utb\Desktop\RockScissorsPaper\node_modules\underscore\underscore.js:1184:21)
at Function.exports.underscore.render (C:\Users\ryan-utb\Desktop\RockScissorsPaper\node_modules\consolidate\lib\consolidate.js:410:14)
at C:\Users\ryan-utb\Desktop\RockScissorsPaper\node_modules\consolidate\lib\consolidate.js:106:23
at C:\Users\ryan-utb\Desktop\RockScissorsPaper\node_modules\consolidate\lib\consolidate.js:90:5
at fs.js:266:14
at Object.oncomplete (fs.js:107:15)
but I already defined win properly, what seems to be the problem?

User.update(
{username:req.body.username},
{ win : req.body.win, lose : req.body.lose, draw : req.body.draw },
function (err, data) { //look - no argument name "user" - just "data"
//2 mistakes here that you should learn to never do
//1. Don't ignore the `err` argument
//2. Don't assume the query returns something. Check that data is not null.
console.log(data);
//The next line must be INSIDE this function in order to access "data"
res.redirect('/user/' + data.username);
});
//ACK don't try to access "data" (or "user") here. this is asynchronous code!
//this code executes EARLIER IN TIME than the User.update callback code
update after your snippet v2
your find call is simply not matching any documents, so user is null
FYI You can do a find and update at the same time with a single findOneAndUpdate operation

User.update({
username: req.body.username
},{
$set: {
win : req.body.name,
loose : req.body.loose
}
}, function(err, result) {
if (err) {
console.log(err);
} else if (result === 0) {
console.log("user is not updated");
} else {
console.log("user is updated");
}
});
I hope you can understand your issue and can update your User collection.

Related

node js and mongodb asynchronous issue

i'm new to mongodb and i'm having problems updating a local variable after a query. i'm using node js and i have a local variable i'm trying to update depending on my query result, but it seems that my functions returns before the query. i understand node js is asynchronous but i'm having trouble dealing with that. you can see my code below:
function userExist(userList, username){
//var usert = new UserSchema()
var exist = false
UserSchema.findOne({userName: username}, function (err, usert) {
if (err) return handleError(err);
if (usert) {
// doc may be null if no document matched
exist = true
}
})
console.log("boolean " + bool)
return exist
// return username in userList
// return query
}
I'm also having a different but unrelated issue where i'm trying to extract a specific value from a query result. my schema is as follow:
//import dependency
var mongoose = require('mongoose')
var Schema = mongoose.Schema
//create new instance of the mongoose.schema. the schema takes an
//object that shows the shape of your database entries.
var UserSchema = new Schema({
userName: String,
userID: String,
Conversations: [
{
conversationID: String,
messages: [
{
message: String,
messageID: String,
sender: String,
time: String
}
]
}
]
})
//export our module to use in server.js
module.exports = mongoose.model('User', UserSchema)
i'm trying to get the values in conversations array, add a new conversation to it and push it back in the database.
An answer to either question would be really helpful and appreciated.
just for clarification this is where i'm using the userExist function:
//Verify Username
socket.on(VERIFY_USER, (nickname, callback)=>{
if(userExist(connectedUsers, nickname)){
console.log("user exist")
callback({ userExist:true, user:null })
}else{
console.log("user does not exist")
callback({ userExist:false, user:createUser({name:nickname, socketId:socket.id})})
}
})
As already pointed out the findOne returns a promise.
You can handle the promise executing callbacks on the success or fail of the findOne result
Define two functions to pass as callbacks
function success(user){
//no error check
//doc has been found
//do something
} ;
function fail(err){
console. log(err)
}
Then in the findOne function body
if (err) return fail(err) ;
//else
return success(user)
OR
you can wrap the userExist function body to return a promise
function userExist(userList, username){
return new Promise(function(resolve, reject){
var exist = false
UserSchema.findOne({userName: username}, function (err, usert) {
if (err) return reject(err);
if (usert) {
// doc may be null if no document matched
exist = true
resolve(exist)
}
})
})
}
And when you call the userExist
userExist(userList, username).then(function(user){
//do something with the user
}).catch(function(reason) {
console.error(reason);
});

MongoDB Duplicate Key Error

So right now, I'm working on a service to allow multiple events to store data on MongoDB. They store event data by creating new collections on MongoDB every time a new event comes on. If the same event needs to store a different set of data, a new document in MongoDB should be created.
The code below is the service I created to handle this.
import WhiteBoardEvent from '../model/event.model';
import IEventStore from '../interface/eventStore.interface';
import * as MongoClient from 'mongodb';
export class EventStore implements IEventStore {
private mongoDBEndpoint = "mongodb://192.168.10.10:27017";
public insert(event: WhiteBoardEvent, callback: (err: any) => void): void {
MongoClient.connect(this.mongoDBEndpoint, { connectTimeoutMS: 1000 }, (connErr, db) => {
if (connErr) { db.close(); callback(connErr); return; }
this.getNextSequence(db, event, (err, sequence) => {
if (err) { db.close(); callback(err); return; }
event.sequence = sequence;
db.collection(event.roomId).insert(event, (err) => {
db.close();
callback(err);
});
});
});
}
private createCounterCollection(db: MongoClient.Db, event: WhiteBoardEvent, callback: (err: any) => void): void {
db.collection("counters").insert({
roomId: event.roomId,
sequence: 0
}, callback);
}
private getNextSequence(db: MongoClient.Db, event: WhiteBoardEvent, callback: (err: any, sequence: number) => void): void {
var collection = db.collection("counters");
collection.findOneAndUpdate(
{ roomID: event.roomId },
{
$inc: { sequence: 1 },
// new: true
},
{
upsert: true,
returnOriginal: false
},
(err, r) => {
if (err) {
this.createCounterCollection(db, event, (err) => {
if (err) { callback(err, -1); return; }
callback(null, 0);
});
return;
}
callback(null, r.value.sequence);
console.log("counter : " + r.value.sequence);
}
);
}
}
The following code is a test file I created so that I can see the changes in MongoDB.
import * as timers from 'timers';
import WhiteBoardEvent from './data/model/event.model';
import { EventStore } from './data/service/eventStore.service';
var model = new WhiteBoardEvent();
model.name = "t2";
model.roomId = "testRoom";
model.timestamp = new Date();
model.userId = "";
var model2 = new WhiteBoardEvent();
model2.name = "t1";
model2.roomId = "testRoom2";
model2.timestamp = new Date();
model2.userId = "";
var eventStore = new EventStore();
var timer1 = timers.setInterval(()=>{
eventStore.insert(model, (err)=>{
if(err){
console.log(err);
}else{
console.log("Test Completed!");
}
});
}, 1000);
var timer2 = timers.setInterval(()=>{
eventStore.insert(model2, (err)=>{
if(err){
console.log(err);
}else{
console.log("Test Completed!");
}
});
}, 1000);
This is a snippet of the output I get. Here, "Test Completed" is shown for the first instances, after that, I'm getting the duplicate errors.
counter : 1
counter : 1
Test Completed!
Test Completed!
counter : 2
{ MongoError: E11000 duplicate key error collection: admin.testRoom index:
_id_ dup key: { : ObjectId('59d5da14cedd6f28a5db8c93') }
Can anyone help me with this? Thank you in advance!
You are creating two instances of WhiteBoardEvent without explicitly setting an ID (this is fine, but relevant). Have a look at this excerpt from your code above:
db.collection(event.roomId).insert(event, (err) => {
db.close();
callback(err);
});
After handing event over to MongoDB's insert, it is checked to see if it has an ID - it does not. Because of this, the MongoDB code generates an ID for you (see here). This is all great - it's what you want.
However, what happens the next time your setInterval callback is invoked? Well, model and model2 now have an ID set - it was set according to the rules I just described. In this case, now that there's an ID set on the model going into insert, you are trying to reuse the same ID as the MongoDB code leaves it alone.
In your test code, you could simply clear out the ID in your eventStore.insert callback to ensure that a new ID is generated every time. e.g.:
eventStore.insert(model, (err)=>{
model._id = null;
if(err){
console.log(err);
}else{
console.log("Test Completed!");
}
});
It is likely that in your scheme you have you have a key set on unique: true.
Adding another object with the same key or a key not filled in will result in a duplicate key error. Because, if a field is not filled in it will be filled in with null. So 2 times null is a duplicate key error. To make sure this will not happen.
Use sparse: true instead of unique: true. Also note that a field with unique: true is never able to have two of the same keys. Sparse is only able to have multiple nulls(undefined) inside and works the same as unique: true further.
In your case you have to times the userid on "", this will probably cause the error if its set on unique.model.userId = "";
Hope this will solve your answer. Else please show us your model.
Sven

MongoDB - Save vs Update for specific fields in document

Using the MEAN stack, I'm attempting to have an admin account update another user's information, in this case, their title/role on the site. The problem I have is that the only function available when editing a user is the save() function. It might be that I can utilize the update function, and if that is the case please let me know, but it doesn't look possible:
The problem arises that when the user is saved, it creates a new document, and overwrites the user's password and salt to some value. I'd like to be able to call an "update" function that will only update the one field, but I can't figure out how to. Is there a way to do this with the save function?
Relevant Code:
exports.updateUserRoles = function(req, res) {
var currUser = req.body;
User.findById(currUser._id, function(err, user) {
//user.roles = currUser.roles;
user.save( { _id : '56467b28ba57d8d890242cfa', roles : 'admin' } );
//THE BELOW WAS A PREVIOUS ATTEMPT
/*user.save( function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(user);
console.log('test2');
}
});*/
});
};
Trying something else that seems very close, but still not quite there yet.
Here's what I'm running:
exports.updateUserRoles = function(req, res) {
var currUser = req.body;
User.findById(currUser._id, function(err, user) {
//user.roles = currUser.roles;
//user.roles.set(0, 'admin');
console.log('test');
user.update(
{ _id: '56467b28ba57d8d890242cfa' },
{
$set: {
roles: 'admin',
},
}
);
console.log('test2');
});
};
Upon hitting the user.update line, we have the user in the local variables, seen:
user.update goes into this Document.prototype.update function, seen:
The args look to be building right, which _id we are targeting and what the action is, seen:
But then after running, nothing seems to change. I'm very much stumped.
For updates various fields in mongodb you can use update with different atomic operators, like $set, $unset, $push etc.
Example:
var updateUserRoles = function(db, callback) {
db.collection('users').updateOne(
{ "_id", : "user_id", },
{ $set: { "password": "new_password" } },
function(err, results) {
console.log(results);
callback();
}
);
};

Save before req.session.destroy() ExpressJS

I want to save the session value "image location" into the database before I have destroyed the session in logout route
The solution adopted by me is :
app.get('/logout',function(req,res){
Person.update({ username: req.session.user_name }, { $set: {lastimage: req.session.userimage[req.session.img_idx]}}, function(error,update)
{
if(update){
req.session.destroy(function() {
res.end();
});
if(error){
console.log(error);
res.end();
}
}
});
});
But when I am using this get location route the task is accomplished i.e the value in person db is updated but in return there is some weird error shown
TypeError: Cannot read property 'undefined' of undefined
at options.key (/opt/expressjs/app.js:381:94)
at callbacks (/opt/expressjs/node_modules/express/lib/router/index.js:164:37)
at param (/opt/expressjs/node_modules/express/lib/router/index.js:138:11)
at pass (/opt/expressjs/node_modules/express/lib/router/index.js:145:5)
at Router._dispatch (/opt/expressjs/node_modules/express/lib/router/index.js:173:5)
at Object.router (/opt/expressjs/node_modules/express/lib/router/index.js:33:10)
at next (/opt/expressjs/node_modules/express/node_modules/connect/lib/proto.js:193:15)
at resume (/opt/expressjs/node_modules/express/node_modules/connect/lib/middleware/static.js:65:7)
at SendStream.error (/opt/expressjs/node_modules/express/node_modules/connect/lib/middleware/static.js:80:37)
at SendStream.EventEmitter.emit (events.js:95:17)
Why is it so. I am using ExpressJs sessions and mongodb
P.S: The line /opt/expressjs/app.js:381:94 is
Person.update({ username: req.session.user_name }, { $set: {lastimage: req.session.userimage[req.session.img_idx]}}, function(error,update)
Have you tried saving
'req.session.userimage[req.session.img_idx]' in some var before use ?
for example:
var uName = req.session.user_name,
uImage = req.session.userimage[req.session.img_idx];
Person.update({ username: uName }, { $set: {lastimage: uImage }}, function(error,update) { ...
BTW, you may be calling res.end() twice, which will make things weird.
EDIT:
app.get('/logout', function(req,res) {
var uName = req.session.user_name,
uImage = req.session.userimage[req.session.img_idx];
Person.update({ username: uName }, { $set: {lastimage: uImage }}, function(error,update) {
if(error)
console.log(error);
// This actually destroys the session
delete req.session;
res.end();
});
});

How to create an update function on nodejs/mongodb?

Hi I am currently new to nodejs and mongodb what I want to do is make a function to update my win,lose,draw record from my userschema.
My Schema:
UserSchema = new mongoose.Schema({
username:'string',
password:'string',
email:'string',
//Change Made
win:{ type: Number, default: 0 },
lose:{ type: Number, default: 0 },
draw:{ type: Number, default: 0 }
});
My Function for updating:
//Update scores
app.post("/user/updateScores", function (req, res) {
var user = new User({
username:req.body.username,
win:req.body.win,
lose:req.body.lose,
draw:req.body.draw
});
Users.findOne({ username : req.params.username }, function(error, user) {
if (error || !user) {
res.send({ error: error });
} else {
user.update(function (err, user) {
if (err) res.json(err)
req.session.loggedIn = true;
res.redirect('/user/' + user.username);
});
}
});
});
The problem is when I try updating, when I try updating via my html file. It does not update anything and just stays the same (the values win,lose,draw the default value is 0 so when I logout and login again the values of the win,lose,draw record is still zero). I thoroughly checked if the problem was the html and javascript functions that I have made but this is not the case so I think that the problem is the update function I have made. Any of you guys have an idea where I went wrong? Thanks!
Assuming your post is being called correctly from the client, you'll need to be careful about variable and parameter names, as the scope right now is that you're saving an exact duplicate of the user object that was just fetched via findOne.
You had user declared as a variable of the post callback, and then again within the findOne. The inner variable user will take precedence.
app.post("/user/updateScores", function (req, res) {
var username = req.body.username;
Users.findOne({ username : username }, function(error, user) {
if (error || !user) {
res.send({ error: error });
} else {
// update the user object found using findOne
user.win = req.body.win;
user.lose = req.body.lose;
user.draw = req.body.draw;
// now update it in MongoDB
user.update(function (err, user) {
if (err) res.json(err) {
req.session.loggedIn = true;
}
res.redirect('/user/' + user.username);
});
}
});
});

Categories

Resources