I'm trying to use mongoose .select operator with my azure function but it keeps saying TypeError: db.collection(...).findOne(...).select is not a function at db.collection.find.toArray
It returns the user's data in the console, but doesn't filter it down with .select
Why is that?
var MongoClient = require('mongodb').MongoClient;
var Post = require('./model/post');
var mongoose = require('mongoose');
module.exports = async function (context, req) {
let currentPage = 1;
MongoClient.connect(process.env.CosmosDBConnectionString, async (err, client) => {
let send = response(client, context);
if (err) send(500, err.message);
let db = client.db(process.env.dbName);
await db.collection('listings').find(
{
$and: [
{ winnerHasBeenNotified: false },
{ auctionEndDateTime: { $lte: Date.now().toString() } }
]
}
)
.toArray((err, result) => {
console.log("result");
console.log(result);
if (result) {
for (let i = 0; i < result.length; i++) {
db.collection('users').findOne(
{
_id: mongoose.Types.ObjectId(result[i].bidderId)
}
).select("notificationBy").toArray((err, result) => {
console.log("USER RESULT!");
console.log(result);
});
}
}
if (err) send(500, err.message);
send(200, JSON.parse(JSON.stringify(result)));
});
});
};
function response(client, context) {
return function (status, body) {
context.res = {
status: status,
body: body
};
client.close();
context.done();
};
}
find() returns a cursor, which has a select method. findOne() retrieves a single document and returns a promise if no callback is provided.
If you are trying to get just the "notificationBy" field, try passing the fields option to findOne.
Related
function getUserByStudentId(NIM) {
db.query('SELECT * FROM data_admin WHERE id_mahasiswa = ?', [NIM], async (err, result) => {
if (!result) {
return null
} else {
var data = await {
id: result[0].id_Admin,
email: result[0].email,
jabatan: result[0].jabatan,
password: result[0].password,
id_mahasiswa: result[0].id_mahasiswa,
id_Acara: result[0].id_Acara,
id_Organisasi: result[0].id_Organisasi
}
console.log(data) // there is a value here
return data
}
})
}
console.log(getUserByStudentId('1301194051')) // undefined returned
I'm a student and start learning nodejs. Would you explain to me, why my function returning undefined
console.log(getUserByStudentId('1301194051')) // undefined
but when I console.log on the function I got returned value
I'll promisify the function for you:
function getUserByStudentId(NIM) {
return new Promise(function(resolve, reject) => {
db.query('SELECT * FROM data_admin WHERE id_mahasiswa = ?', [NIM], (err, result) => {
if (!result) {
resolve(null);
} else {
var data = {
id: result[0].id_Admin,
email: result[0].email,
jabatan: result[0].jabatan,
password: result[0].password,
id_mahasiswa: result[0].id_mahasiswa,
id_Acara: result[0].id_Acara,
id_Organisasi: result[0].id_Organisasi
}
console.log(data) // there is a value here
resolve(data);
}
});
});
}
If you're going to use this function in global scope, use then:
getUserByStudentId('1301194051').then(result => {
console.log(result);
});
If you want to use this function inside an async function, you can await the result:
async function doSomethingWithUser(NIM) {
const user = await getUserByStudentId(NIM);
}
For example, if you're using express:
app.get('/user/:id', async (res, req) => {
const NIM = req.param.id;
const user = await getUserByStudentId(NIM);
res.json({ user });
});
The callback function is not working as expected in a waterfall on async.for each limit.
When I remove that rest api call and if I call callback(null,arg2) it is working as expected, I think the problem with callback function or some api call in the below code.
var async = require("async");
var users = [1, 2, 3, 45]; // Initialize user array or get it from DB
var e = [];
var unirest = require("unirest");
var data = function() {
return new Promise((resolve, reject) => {
async.forEachLimit(
users,
1,
function(user, userCallback) {
async.waterfall(
[
function(callback) {
console.log(user);
callback(null, user);
},
function(arg1, callback) {
console.log(arg1);
callback(null, arg1);
},
function(arg2, callback) {
unirest
.get("http://dummy.restapiexample.com/api/v1/employee/1")
.end(function(response) {
if (response.error) callback("null", "data");
else callback(null, arg2);
});
}
],
function(err, result) {
if (err) {
console.log("err");
reject(e);
} else {
console.log("done", result);
e.push(result);
userCallback();
resolve(e);
}
}
);
},
function(err, result) {
console.log("User For Loop Completed", err, result);
}
);
});
};
I'm getting output as
expected outputs as
Acoording to the data available ui should get 2 reults but getting only one since i put res.send in the looop so it is getting ended ,can anyone help me out please.......
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
record.find(item).toArray((err, result) => {
if (err) {
return
}
if (result) {
for (var i in result) {
var id = result[i].recieved_id;
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
return
}
if (resp) {
console.log(resp);
} else {}
});
}
res.send(resp);
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
}
The problem is in getting the profiles. You are using mongodb's find which is asynchronous. Therefore in your for cycle you start fetching the profiles, but then you send out the res.send well before the fetching of the profiles is finished.
The call back from profile.find(... will be executed after the res.send. Apart from this, the resp variable is inside the find callback and you are trying to res.send it outside.
To deal with this, either you use async or promises. See the below code that uses promises.
var Promise = require('bluebird')
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
record.find(item).toArray((err, result) => {
if (err) {
return
}
if (result) {
var profiles_to_get = []
var profiles = []
for (var i in result) {
var id = result[i].recieved_id;
profiles_to_get.push(get_profile(id, profiles))
}
Promise.all(profiles_to_get)
.then(() => {
res.send(profiles);
})
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
function get_profile (id, profiles) {
return new Promise(function (resolve, reject) {
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
reject(err)
return
}
if (resp) {
profiles.push(resp)
resolve()
} else {
reject()
}
});
})
}
}
How this works is that it creates a list of profiles to find and stores it in the var profiles_to_get = []. The you use Promise.All(profiles_to_get) which will let you do stuff after all the profiles have been fetched.
You can send only one response back to a request.
Define a variable outside the for loop, append records to it and then send it after the for loop has ended.
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
var resList = [];
record.find(item).toArray((err, result) => {
if (err) {
return
}
if (result) {
for (var i in result) {
var id = result[i].recieved_id;
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
return
}
if (resp) {
console.log(resp);
resList[i] = resp;
}
else{
}
});
}
}//end of if loop
else {
resList = {
status: 'fail',
data: []
};
}
res.send(resList);
});
Don't use for loop in asynchronous mode. Use async module instead like below.
var async = require('async');
exports.getrequestsdetails = function (req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
record.find(item).toArray(function (err, result) {
if (err) {
return
}
if (result) {
var list = [];
async.each(result, function (item, cb) {
var id = item.recieved_id;
var profile = db.collection('profile');
profile.findOne({
'_id': new ObjectId(id)
}, function (err, resp) {
if (err) {
return cb();
}
if (resp) {
list.push(resp);
console.log(resp);
return cb();
}
return cb();
});
}, function (err) {
res.send(list);
});
}//end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
}
You can push all the resp in list array and send after completing loop.
Like this:
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params);
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
};
record.find(item).toArray((err, result) => {
if (err) {
return err;
}
if (result) {
var list = [];
for (var i in result) {
var id = result[i].recieved_id;
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
return err;
}
else{
list.push(resp);
console.log(resp);
if(i===result[result.length-1]){
res.send(list);
}
}
});
}
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
};
Hope this work for you
You can add all the list in to an array and finally send the data after the loop
Hi I have this code but when finish the result is not the espected because didn't run in the sequence that I wish
here is the code:
var user_data = {};
models.games.find({$or: [{w_id: req.user._id}, {b_id: req.user._id}, {owner: req.user._id}]}, function (err, games) {
var req_games = [];
if (!err) {
for (var i in games) {
req_games.push(games[i]);
models.users.findOne({_id: games[i].w_id}, function (err, user) {
req_games[i].w_id = user.user;
console.log(req_games[i].w_id) //< -- 3
});
console.log('a ' + req_games[i].w_id) //<-- 2
}
user_data.games = req_games; // <-- 1
}
});
at the end of the task req_games didnt have any update because it's running in the sequence that I put in the comments in the code
This may help you using Q(promises)
obj.find = function(model, condition) { //make your find to return promise
var deferred = q.defer();
model.find(condition, function(err, results) {
if (err) {
logger.log(err);
deferred.reject(err);
} else {
deferred.resolve(results);
}
});
return deferred.promise;
}
ArraysOfId.forEach(function (id) {
var tempProm = mongoUtilsMethodObj.find(schemaObj.Asset, id).then(function (assetObj) {
---- your code
return q.resolve();
});
promArr.push(tempProm);//push all promise to array
});
q.all(promArr).then(function () {
// this will be called when all promise in array will we resolved
})
Here is a version using the async library to map your game values.
var async = require('async');
var user_data = {};
models.games.find({$or: [{w_id: req.user._id}, {b_id: req.user._id}, {owner: req.user._id}]}, function (err, games) {
if(err) {
// or whatever your error response happens to be
return res.render('user.swig', {error: err});
}
async.map(games, function(game, nextGame) {
models.users.findOne({_id: game.w_id}, function (err, user) {
game.w_id = user.user;
nextGame(err, game);
});
}, function(err, req_games) {
user_data.games = req_games;
res.render('user.swig', {user: user_data});
});
});
When I run collection.find() in MongoDB/Node/Express, I need to return value for my array like this but iam in callback hell;
foursquare.getVenues(params,function(error, venues) {
if (!error) {
var places = [];
venues.response.venues.forEach(function(e) {
places.push(
{
obj_id:e.id,
name:e.name,
distance:e.distance,
here_now:req.collection.findById(e.id) //count- i want need this value
}
);
});
res.send(places);
}
});
You can try to use Async https://github.com/caolan/async#each
var async = require('async');
...
foursquare.getVenues(params, function (error, venues) {
if (!error) {
throw err;
}
var places = [];
async.each(venues.response.venues, function (e, callback) {
db.collection.findById(e.id, function (err, res) {
places.push({
obj_id: e.id,
name: e.name,
distance: e.distance,
here_now: res
});
callback()
});
}, function (err) {
if (err) {
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
res.send(places);
}
});
});
or Using async.map
var async = require('async');
var createArray = function (e, cb) {
db.collection.findById(e.id,function(err,res){
var obj = {
obj_id: e.id,
name: e.name,
distance: e.distance,
here_now: res
}
cb(null, obj);
});
}
async.map(venues.response.venues, createArray, function (err, places) {
if(err){
throw err;
}
console.log(places);
});