Mongoose multiple queries return after second query - node.js

I am trying to get back 'image' with username and url properties included, but it seems that the first query returns first. Apologies for my rookie knowledge.
exports.getImg = (req, res) => {
Image.find({}, '-__v').lean().exec((err, images) => {
if (err) {
res.sendStatus(400)({ 'msg': 'Something went wrong' });
}
for (let i = 0; i < images.length; i++) {
//trying to get
User.findOne({ _id: images[i].id}, (err, user) => {
images[i]['username'] = user.uname;
images[i]['url'] = req.protocol + '://' + req.get('host') + '/images/' + images[i]._id;
});
}
// console.log(images);
// res.json(images);
})
}

It is due the reason that, .find() function is asynchronous.As you are looping and also using .find() in the loop so it will not give the desrired result. You need to use async/await.
exports.getImg = async (req, res) => {
Image.find({}, '-__v').lean().exec(async(err, images) => {
if (err) {
res.sendStatus(400)({ 'msg': 'Something went wrong' });
}
for (let i = 0; i < images.length; i++) {
//trying to get
await User.findOne({ _id: images[i].id}, (err, user) => {
images[i]['username'] = user.uname;
images[i]['url'] = req.protocol + '://' + req.get('host') + '/images/' + images[i]._id;
});
}
// console.log(images);
// res.json(images);
})
}

Related

Unable to return value from function

I'm getting undefined on return value from the function
function checkAveStorage(path) {
console.log("path " + path);
disk.check(path, function(err, info) {
if (err) {
console.log(err);
return -1;
} else {
console.log("info " + info.available);
return ((info.available / info.total) * 100).toFixed(2);
}
});
}
app.get("/sysinfo", (req, res, next) => {
var storage = checkAveStorage('/mnt/usb');
console.log(storage);
})
undefined value appear in console.
You are using callback which cannot return value, but you can use it inside that call back only. Other options are use promise or async/await.
function checkAveStorage (path) {
console.log('path ' + path)
return new Promise((resolve, reject) => {
disk.check(path, function (err, info) {
if (err) {
console.log(err)
reject(-1)
} else {
console.log('info ' + info.available)
resolve(((info.available / info.total) * 100).toFixed(2))
}
})
})
}
app.get('/sysinfo', (req, res, next) => {
checkAveStorage('/mnt/usb').then((storage => {
console.log(storage)
}), (err) => {
console.log(err)
})
})
Another way with async/await
async function checkAveStorage(path) {
try{
const info = await disk.check(path);
return ((info.available / info.total) * 100).toFixed(2);
} catch(err){
console.log(err);
return -1;
}
}
app.get("/sysinfo", async (req, res, next) => {
var storage = await checkAveStorage('/mnt/usb');
console.log(storage);
})
You are using callback so you must :
app.get("/sysinfo", (req, res, next) => {
checkAveStorage('/mnt/usb').then((storage)=>{
console.log(storage)
})

Using return value in another file in Node.js synchronously

I'm concatenating tweets from a defined user through a helper file and trying to retrieve it in my server.js but there the str value is still undefined (and this line gets executed first), then the console.log from my helper prints with the right value.
Output:
GET /login/twitter/callback 302 618.242 ms - 0
Concatenated Tweets in Server: undefined
Concatenated Tweets in Helper: Test Tweet 3 #TestTweet Test Tweet 2
Test Tweet 1
Can anyone help on what control flow I should use to call twitterHelper.getTweets functions to get the returned str in the server please? Thanks!
Server.js
app.get('/login/twitter/callback',
passport.authenticate('twitter', {failureRedirect: "/login"},
function(req, res) {
// auth success
async.waterfall ([
function(callback) {
callback(null, twitterHelper.getTweets(user));
},
function(str, callback) {
console.log("Concatenated Tweets in Server: " + str);
callback(null);
}
],
function(err) {
if(err)
console.log("Error: " + err);
}
);
}
)
);
Helper.js
var concatTweets = '';
var promise = new Promise(
function(resolve, reject) {
T.get('statuses/user_timeline', params, function( err, data, response) {
if(err)
reject(err);
else {
for (var i = 0; i < data.length ; i++)
concatTweets = concatTweets + " " + data[i].text;
resolve(concatTweets);
}
})
}
).then(
str => {
console.log("Concatenated Tweets in Helper: " + str);
return str;
}, err => {
console.log(err);
return err;
}
);
Instead of using this longway you can use this simple way by promise.
Helper.js
var concatTweets = '';
var getTweets = function(user){
var promise = new Promise(function(resolve, reject) {
T.get('statuses/user_timeline', params, function( err, data, response) {
if(err){
reject(err);
} else {
for (var i = 0; i < data.length ; i++)
concatTweets = concatTweets + " " + data[i].text;
console.log("Concatenated Tweets in Helper: " + concatTweets);
resolve(concatTweets);
}
})
});
return promise;
}
Server.js
app.get('/login/twitter/callback', passport.authenticate('twitter', {failureRedirect: "/login"},function(req, res) {
// auth success
twitterHelper.getTweets(user).then(str=>{
console.log("Concatenated Tweets in Server: " + str);
}).catch(err=>{
console.log("Error: " + err);
});
}));
I hope this will work for you.

cloudinary multiple .jpg uploads NODE.JS

has any one of you tried to upload 50+ images to cloundinary? I been trying but the issue is that promise does not get resolved (even with .reflect() and fails to upload all images. Depending on the speed of uploads, it will fail 30% ~ 70%.
Is there any ways to completely make it async and make sure all images are uploaded correctly? Only modules that I am using is bluebird and cloudinary module from their doc.
Promisebd = require('bluebird');
function uploadimg(img, i, itemId) {
var pubID = 'a2z/toys/' + itemId + '/' + i;
// return new cloudImg.v2.uploader.upload(img, {
return cloudinary.v2.uploader.upload(img, { // works
public_id: pubID,
quality: 90
// use_filename: true,
} , function(err, res){
if(err) {
console.log(err);
}
console.log(res);
});
}
promiseArr.push(uploadimg(fullimg, i, d[0].details.detailsProductId)); // pushing the promises to Arr
Promisebd.all(promiseArr.map(function(promise) {
return promise.reflect();
})).each(function(inspection) {
if(inspection.isFulfilled()) {
console.log('The promise is the arr was fulfilled with ', inspection.value());
}else{
console.log('The promise is NOT the arr was NOT fulfilled with ', inspection.reason());
}
})
promsify your upload img function and try to use it
function uploadimgAsync(img, i, itemId) {
return new Promise(function (resolve, reject) {
var pubID = 'az/toys/' + itemId + '/' + i;
cloudinary.v2.uploader.upload(img, { // works
public_id: pubID,
quality: 90
},
function(err, res){
if(err) {
reject(err);
}
resolve(res);
});
});
}

redirect after a POST to mongodb not working

I'm going crazy!
I'm writing a simple messageboard with node/mongoDB where the user can open threads and comment on them.
After a POST to /newthread, which inserts the data to the DB (which works), I have a redirect to the _id of the document, but the server crashes with "Cannot read postTitle of undefined".
If I then restart the server and navigate to the thread (which is then shown on the index-page, as it was correctly inserted), I can view the thread without a problem.
only after I insert it and redirect, there seems to be no document found.
I really can't figure out why, can someone help?
//index.js
router.post('/newthread', function(req, res) {
threads.save(req, res);
});
//threads.js
var db = require('./db');
var uri = 'mongodb://localhost:27017/project';
var coll = 'documents';
var Oid = require('mongodb').ObjectId;
module.exports.loadAll = function(cb) {
db(uri, {}, function(err, db) {
db.collection(coll, function(err, collection) {
collection.find(
{
$query: {},
$orderby: { "bumpedAt": -1 }
}
).toArray(function(err, items) {
console.log("Found items: " + items.length);
cb(null, items);
})
});
})
};
module.exports.loadOne = function(id, cb) {
db(uri, {}, function(err, db) {
db.collection(coll, function(err, collection) {
if (err) {
console.log(err);
} else {
console.log("searching for id: " + id);
console.log("converted to Oid: " + new Oid(id));
collection.findOne({
_id: new Oid(id)
}, {}, function(err, item) {
if (err) {
console.log("error " + err);
cb(err);
} else if (item) {
console.log("Found item!");
console.dir(item);
cb(null, item);
} else {
console.log("Found NO items");
cb(err);
}
})
}
})
})
};
module.exports.save = function(req, res) {
db(uri, {}, function(err, db) {
db.collection(coll, function(err, collection) {
var time = new Date();
console.log("Saving...");
collection.insert({
"op" : req.body.username ||"Anonymous",
"postTitle" : req.body.posttitle || "No Title",
"postContent" : req.body.postcontent,
"createdAt" : time,
"bumpedAt" : time,
"comments" : []
}, function (err, doc) {
if (err) {
res.send ("Error while saving your post.")
} else {
console.log("Saved!");
console.dir(doc);
var threadId = new Oid(doc._id).toString();
res.location('/thread/' + threadId);
console.log("reloacting to " + threadId);
res.redirect('/thread/' + threadId);
console.log("redirecting to " + threadId);
}
})
})
})
};
//thread.js (route to /thread/:id)
router.get('/:id', function(req, res) {
console.log("loading " + req.params.id);
threads.loadOne(req.params.id, function(err, item) {
if (err) {
console.log(err);
} else {
res.render('showthread', {
title: item.postTitle,
posts: item
})
}
})
});
console output for saving a thread is:
Saving...
Saved!
{result: { ok: 1, n: 1 },
// ...
}
relocating to 557d2305be8e753b0e0cf70a
redirecting to 557d2305be8e753b0e0cf70a
POST /newthread 302 96.992 ms - 120
loading 557d2305be8e753b0e0cf70a
searching for id: 557d2305be8e753b0e0cf70a
converted to Oid: 557d2305be8e753b0e0cf70a
Found NO items
TypeError: Cannot read property 'postTitle' of undefined
at [...]/thread.js:16:28
(that's at "title: item.postTitle,")
am I accessing it wrong?
The id is read, and it is correct. on the index, links are generated exactly from the _id, so this is totally correct. If I click an index link, I can see the thread. The redirected (after POST) url even shows the correct link (with that same id), but I can't loadOne with that id just after posting... why??

ldap query get all users in a group node.js

failing to find any info on the matter.
I need to query an active directory server with a specified group name, and to receive back all the users it contains.
Then i can iterate through those users and use their first&last name + email + phone + accountname.
Is all that possible using Node.js?
Can someone liberate me from this headache?
Using this link:
https://www.npmjs.com/package/activedirectory#getUsersForGroup
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
ad.getUsersForGroup(groupName, function(err, users) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! users) console.log('Group: ' + groupName + ' not found.');
else {
console.log(JSON.stringify(users));
}
});
The other solution posted is for ActiveDirectory, as a more general answer, you need a query which will return the "member" attribute from a group.
I was able to accomplish this using ldapjs
import ldap from 'ldapjs'
const client = ldap.createClient({ url: ['ldap://localhost:389'] })
client.on('error', (err) => { console.log(err) } )
client.bind("cn=admin,dc=example,dc=com", "password", (err) => {console.log(err)})
function logCallback(err,res) {
if(!res) {
console.log(err)
return
}
res.on('searchRequest', (searchRequest) => {
console.log('searchRequest: ', searchRequest.messageID);
});
res.on('searchEntry', (entry) => {
console.log('entry: ' + JSON.stringify(entry.object));
});
res.on('searchReference', (referral) => {
console.log('referral: ' + referral.uris.join());
});
res.on('error', (err) => {
console.error('error: ' + err.message);
});
res.on('end', (result) => {
console.log('status: ' + result?.status);
});
}
client.search("dc=example,dc=com",{filter:"(&(objectclass=groupofnames)(cn=users))",scope:"sub"},logCallback)
> searchRequest: 8
entry: {"dn":"cn=users,ou=Groups,dc=example,dc=com","controls":[],"cn":"users","description":"All Users","member":["uid=user,ou=Users,dc=example,dc=com","uid=user1,ou=Users,dc=example,dc=com","uid=user2,ou=Users,dc=example,dc=com"],"objectClass":["groupOfNames","top"]}
status: 0
The return value has a field "member" with a list of all users in the group.
exports.getUserLists = (req, res) => {
var ActiveDirectory = require('activedirectory');
var ad = new ActiveDirectory({
url: 'domainName.com',
baseDN: 'dc=domain,dc=com',
});
var opts = {
includeMembership: ['user'], // can use 'all','group','user'
baseDN: 'cn=users,cn=accounts,dc=domain,dc=com',
includeDeleted: false
};
ad.find(opts, function (err, results) {
if ((err) || (!results)) {
res.send('ERROR: ' + JSON.stringify(err));
return;
}
res.send(JSON.stringify(results))
});

Resources