I have an array of userIDs (MongoDB Objectids)which I want to iterate through and for each one, find its user entry in my MongoDB database of users, and update it, say modify the user's age. Then only when every user has been updated, do I want to say res.send(200); in my Node.js Express app.
I started out with the following code which is just plain wrong because of the asynchronous calls to findById:
for (var i = 0; i < userIDs.length; i++) {
var userID = userIDs[i];
User.findById(userID, function (err, user) {
if (err) throw err;
// Update user object here
user.save(function (err, user) {
if (err) throw err;
res.send(200);
});
});
}
Any ideas how I can do this? Is there perhaps a synchronous version of findById? Or perhaps a way to map through the array and apply a function to each element?
Thanks!
I think you want the forEach method of npm's async module. It would look something like this:
async.forEach(userIDs, function(id, callback) {
User.findById(id, function(err, user){
if(err) throw err;
user.save(function(err, user){
if(err) throw err;
callback();
}
}, function(err){
if(err){
throw err;
} else {
res.send(200);
}
}
}
The best way is to use promises.
An example with Q#all:
var q = require('Q');
var promises = userIDs.map(function(userID){
var deferred = q.defer();
User.findById(userID, function (err, user) {
if (err) return deferred.reject(err);
// Update user object here
user.save(function (err, user) {
if (err) return deferred.reject(err);
deferred.resolve(user);
});
});
return deferred.promise;
});
q.all(promises)
.then(function(users){
res.json(users);
})
.fail(function(err){
res.send(500,err);
});
Related
How can I delete particular data in mongodb using node.js ?
router.post('/deletedata', (req, res) => {
console.log("deleted values are",req.body.id)
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("mohan");
var myquery = req.body.id;
console.log("myquery value is:", myquery)
dbo.collection("customers").remove({myquery}, function(err, obj) {
if (err) throw err;
db.close();
});
});
res.json({
statusCode: 200,
result: "success",
})
}
);
export default router;
I got particular id from React hooks crud app , So i can see the id in node js but it does not delete the that particular id data in mongoDB
Your query will only delete documents with myquery: passedId
I bet query should look like {_id: myquery}
dbo.collection("customers").remove({_id: myquery}, function(err, obj) {
if (err) throw err;
db.close();
});
dbo.collection("customers").remove(myquery, function(err, obj) {
if (err) throw err;
db.close();
});
try using delete({query}) or deleteMany({query})
Good Morning All,
I have been looking for an answer to this on the boards, but my noob brain just can't make sense of it.
i have this function in models/user.js
module.exports.getUserByUsername = function(username, callback){
var retUser = new User;
sql.connect(dbConfig, function(err) {
if (err) {
console.log(err);
callback();
}
// create Request object
var request = new sql.Request();
request.input('ip_username', sql.NVarChar, username)
// query to the database and get the records
request.query('select * from [portal_users] where username = #ip_username', function(err, recordset) {
if (err) {
console.log(err);
return;
} else {
var user = new User(recordset.recordset[0].username,recordset.recordset[0].password,recordset.recordset[0].email,recordset.recordset[0].name);
user.addID(recordset.recordset[0].id);
retUser = user;
}
callback();
// send records as a response
//res.send(recordset);
});
});
function callback() {
sql.close();
return retUser;
};
}
and this code in my routes/user.js
passport.use(new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
I have been modifying an example from GITHUB that uses mongoDB for the DB connection, but I would like to use MS SQL. The function is successfully calling the database and returning the correct values. However I don't know how to initiate the callback so I can pass the retUser object back to the original function for processing and logging in.
I did for a moment try to do this by not using the callback and using a standard return type of function, however I quickly realised that given the async nature this wouldn't work.
any help here would be greatly appreciated.
Thanks
OK I managed to figure it out using this post:
Node.js npm mssql function returning undefined
my new code is:
module.exports.getUserByUsername = function(username, callback){
var connection = new sql.ConnectionPool(dbConfig, function(err) {
if (err) {
console.log(err);
callback(err);
return
}
// create Request object
var request = new sql.Request(connection);
request.input('ip_username', sql.NVarChar, username)
// query to the database and get the records
request.query('select * from [portal_users] where username = #ip_username', function(err, recordset) {
if (err) {
console.log(err);
callback(err,recordset);
return;
} else {
var user = new User(recordset.recordset[0].username,recordset.recordset[0].password.replace(/ /g,''),recordset.recordset[0].email,recordset.recordset[0].name);
user.addID(recordset.recordset[0].id);
callback(err,user);
}
sql.close();
// send records as a response
//res.send(recordset);
});
});
}
I would like to get the whole document instead of the added item when I do a save().
var newTodo = Todos({
ID: req.body.ID,
RuleName: req.body.RuleName
});
newTodo.save(function (err, todos) {
if (err) throw err;
res.send(todos);
});
You cannot get it, unless you extend model method, or get it inside save
Simple version
newTodo.save(function (err, todos) {
if (err) throw err;
Todos.find(err, todos) {
if (err) throw err;
res.send(todos);
}
});
Version with custom method
// in schema definition
TodosSchema.methods.saveAndFind = function(cb) {
var self = this;
self.save(function(err) {
if(err) throw err;
return self.model('Todos').find({}, cb);
})
};
// in controller
var newTodo = Todos({
ID: req.body.ID,
RuleName: req.body.RuleName
});
newTodo.saveAndFind(function (err, todos) {
if (err) throw err;
res.send(todos);
});
I had this function:
exports.profileImage = function(req, res) {
var id = req.params.user_id;
userProvider.get(id, function(err, user){
if (err) throw err;
userProvider.getImageById(user['image_id'], function(err, image) {
if (err) throw err;
userProvider.writeImageToDisk(image, function(err, path){
if (err) throw err;
res.sendfile(path);
});
});
});
};
I rewrite it using local variables:
exports.profileImage = function(req, res) {
var id = req.params.user_id;
var userTemp = undefined;
var imageTemp = undefined;
async.series([
userProvider.get(id, function(err, user){
if (err) throw err;
userTemp = user;
}),
userProvider.getImageById(userTemp['image_id'], function(err, image) {
if (err) throw err;
imageTemp = image;
}),
userProvider.writeImageToDisk(imageTemp, function(err, path){
if (err) throw err;
res.sendfile(path);
})
]);}
I have a parameters which userProvider.getImageById (user json object) needs , it comes from userProvider.get function, Which invoked before, I save it to local variable.
I chose async to skip callback hell but it is not working.
Error:
Cannot read property 'image_id' of undefined.
userTemp is undefined at the point where you try to look up its image_id. It will only become not undefined when the previous asynchronous function has been called.
Using async.waterfall, you should be able to simplify your code considerably to something like (the untested);
var id = req.params.user_id;
async.waterfall([
function(callback) {
userProvider.get(id, callback);
},
function(user, callback) {
userProvider.getImageById(user['image_id'], callback);
},
userProvider.writeImageToDisk,
res.sendfile
]);
That's not how async.series works.
Each function in the array has to have the following signature:
function(callback) { ...; callback(...); };
Once the code for each function is done, you need to call the callback function to signal to async that it should run the next step (docs).
So your code should look like this:
async.series([
function(callback) {
userProvider.get(id, function(err, user) {
if (err) throw err;
userTemp = user;
callback();
});
},
function(callback) {
userProvider.getImageById(userTemp['image_id'], function(err, image) {
if (err) throw err;
imageTemp = image;
callback();
});
},
function(callback) {
userProvider.writeImageToDisk(imageTemp, function(err, path){
if (err) throw err;
res.sendfile(path);
callback();
});
}
]);
Better yet, take a look at async.waterfall for a way of passing results from one async function to the next.
I have an empty database and im getting TypeError: Cannot read property 'id' of undefined
Im not sure how to check for a undefined variable, or even if this check should be in the db model
Express route
app.all("/", function(req, res){
if(!req.isAuthenticated()) req.user = null;
Bid.findHighestBids(function(err, bids){
if(err) throw err;
User.findHighestBidder(bids[0].id, bids[0].amount, function(err, highest){
if(err) throw err;
highest.amount = bids[0].amount;
res.render("home", {user: req.user, bids: req.bids, highest: highest});
});
});
});
Snippet from the models, (there is no data so its not returning anything, which is the problem)
BidSchema.statics.findHighestBids = function(done){
var Bids = this;
var num = 5;
this.find()
.sort('-amount')
.limit(num)
.exec(function(err,bids){
if(err) throw err;
done(null, bids);
});
}
UserSchema.statics.findHighestBidder = function(id, amount, done){
var User = this;
this.findOne({ 'facebook.id' : id }, function(err, highest){
if(err) throw err;
if(!id) return done(null, highest);
done(null, highest);
});
}
You're not checking that bids contains any elements before accessing the first one. Since you say you have no data, that's likely your problem:
Bid.findHighestBids(function(err, bids){
if(err) throw err;
User.findHighestBidder(bids[0].id, bids[0].amount, function(err, highest){
...
bids[0] returns undefined, which has no id property, and thus the error.
So do something like this instead:
Bid.findHighestBids(function(err, bids){
if (err) throw err;
if (bids.length) {
User.findHighestBidder(bids[0].id, bids[0].amount, function(err, highest){
if(err) throw err;
highest.amount = bids[0].amount;
res.render("home", {user: req.user, bids: req.bids, highest: highest});
});
} else {
res.render(... whatever you need for the no bids case ...);
}