Projection in .find() not working for MongoDB/Express [duplicate] - node.js

This question already has answers here:
batchSize field name ignored in Field Projection
(2 answers)
Closed 4 years ago.
I have an express app that's supposed to query my MongoDB database, then return only certain fields of the result. My code for this currently looks like this:
app.get('/stored', (req, res) => {
let pollId = req.query.id;
let pollCursor = db.collection(collName).find({"_id": ObjectId(pollId)}, {"_id": false, "pollName": false}).toArray((err, data) => {
if(err) return err;
let dataObj = data[0];
console.log(dataObj);
});
});
I expect to recieve a data object that contains all fields except the '_id' and 'pollName' fields. However, the object I get still contains both these fields, as well as all the other fields. What am I doing wrong?

The first you have to test like this:
app.get('/stored', (req, res) => {
let pollId = req.query.id;
res.send(pollId)
return;
});
if pollId match with pollId from client send, it's fine. You should create a query to find like this:
let query = {_id: pollId}
This is my code, hope help you
// https://tudiendanhngon.herokuapp.com/author/detail?id=5adc963c7b76157c65d3b1d9
app.get("/author/detail", function (req, res) {
var id = req.query.id;
var query = {_id: id};
db.collection(COLLECTION_AUTHORS).find(query).exec(function (err, author) {
if (err) {
res.send("Error")
} else {
res.json(author);
}
});
});

Related

nodejs pass same variable in two differents middlwares

in my app file i have two post middlwares
app.post('/check',urlencodedParser,function (req, res) {
var date_entre_user=req.body.dateentry;
var date_sortie_user=req.body.datesortie;
var idroom=req.body.room;
let sql=`SELECT * FROM reservation WHERE idchambre = ${req.body.room}`;
let query=db.query(sql,(err,result)=>{
datesortieuser=dateFormat(date_sortie_user,"isoDaTteTime");
dateentreuser= dateFormat(date_entre_user,"isoDateime");
app.post('/submit',urlencodedParser,function (req, res) {
.numtele,
email: req.body.email
}
/* let clt = {
nom: req.body.nom,
prenom : req.body.prenom,
cin: req.body.cin,
ville: req.body.ville,
pays: req.body.pays,
tele: req.body
let sql2 = 'INSERT INTO client SET ?'
db.query(sql2, clt,function (err, result) {
if (err) throw err;
console.log("1 client inserted");
});
let sql3 =`SELECT idclient FROM client WHERE nom = ${req.body.nom}`;
db.query(sql3,function (err, result) {
if (err) throw err;
console.log(result);
});
but when i use the variable date_entre_user in the second middleware post i got variable undefined
how can i do it?
The variable you mentioned is defined only in your first .post() method, so it isn't in scope in the second one.
If you want to pass data from one middleware function to another, a good way is to use req.locals, adorning the req object with the data you're passing. Something like this.
/* in one function */
if (!req.locals) req.locals = {}
req.locals.date_entre_user = quelqueChose
and then in the next function, you can refer to that same item.

Add an incrementing ID property to each object in array after it has been submitted

I am trying to add a unique ID property to each object in an array after it has been submitted from an input & text area. When I console.log the array as I add more entries it looks like so:
[{"title":"hello","text":"sir"}]
I have two const variables I'm using currently. The contents of the note array get written in to a db.json file.
const notes = [];
const newID = 0;
This is an express js program and below is the function I have to write the input data to the appropriate file. I would like to add an ID for each entry preferably in this function.
app.post("/api/notes", (req, res) => {
let newNote = req.body;
notes.push(newNote)
fs.writeFile(path.join(__dirname, 'db/db.json'), JSON.stringify(notes), (err) => {
if (err) throw err;
});
res.end();
});
I've tried to map the new property unsuccessfully I've also tried a forEach to run through the array to add the id++.
Please let me know if there is any pertinent information I am missing here. Thanks in advance for any help/feedback!
I figured out the forEach and the working code is below.
app.post("/api/notes", (req, res) => {
let newNote = req.body;
notes.push(newNote)
notes.forEach((note, index) => {
note.id = index + 1;
});
fs.writeFile(path.join(__dirname, 'db/db.json'), JSON.stringify(notes), (err) => {
if (err) throw err;
});
res.end();
});

Updating fields in array -NodeJs

I have this code that loop through all users in DB then look for specific events based on the id value and if there is a match it should update the field caption with a new given data,
for the code :
1- search all potential user = OK
2 - search and find events based on id = OK
3- update the field caption = NOK
this is my code hope I mentioned everything
router.post('/delete/:id',async (req, res) => {
const eventId = req.params.id // this is the ID of the event
User.find({}).lean(true).exec((err, users) => {
let getTEvent = [];
for (let i = 0; i < users.length; i++) {
if (users[i].events && users[i].events.length) {
for (let j = 0; j < users[i].events.length; j++) {
if (users[i].events[j]._id === eventId) {
console.log('you event is :'+ eventId) // this statement to verify if really got the correct ID or not
users[i].events[j].caption ="deleted" // from here the problem
users[i].save(err => {
if (err) throw err;
console.log("status changed saved");
// Redirect back after the job is done.
});
}
}
}
}
});
})
the error that I get is that users[i].save is not a function I don't know with what should I replace it,
As per comments #whoami
router.post('/delete/:id', (req, res) =>
User.findOneAndUpdate({
"events._id": req.params.id
},
{ $set: { "events.caption": "yesssss" }
}, {upsert: true}, (err, user) => {
if (err) {
res.send('error updating ');
} else {
console.log(user);
console.log(req.params.id)
}
}));
Below the mongoDb and event datastructure
Hope I clarified everything ,
Best Regards,
Actual Issue :
.save() works on mongoose document but not on javaScript object. In your code you've already converted mongoose documents returned from .find() call to .Js objects using : .lean(true).
.lean(true) is used to convert mongoose docs to .Js objects to work manipulate fields inside docs in code.
Fixing code :
const mongoose = require('mongoose');
router.post("/delete/:id", async (req, res) => {
const eventId = req.params.id; // this is the ID of the event
await User.find({})
.lean(true)
.exec((err, users) => {
let getTEvent = [];
for (let i = 0; i < users.length; i++) {
if (users[i].events && users[i].events.length) {
for (let j = 0; j < users[i].events.length; j++) {
if (users[i].events[j]._id === eventId) {
console.log("you event is :" + eventId);
users[i].events[j].caption = "deleted";
users[i]._id = mongoose.Types.ObjectId(users[i]._id); // Converting `_id` string to `ObjectId()` to match with type of `_id` in DB
let user = new User(users[i]); // Create a mongoose doc out of model
user.save((err) => { // As we're passing `_id` in doc to `.save()` it will be an update call rather-than insert
if (err) throw err;
console.log("status changed saved");
// Redirect back after the job is done.
});
}
}
}
}
});
});
As I've mentioned this can be done with out this extra process of reading docs/iteration/update call. Using .updateOne() or .updateMany() along with $ positional operator things can be done in one DB call :
const mongoose = require('mongoose');
router.post("/delete/:id", async (req, res) => {
const eventId = req.params.id; // this is the ID of the event
/** We're using `.updateMany` with filter on `events._id` -
* So that all user docs which has `'events._id': eventId` will be updated,
* If you've a particular user needs to be updated used `.updateOne()` with a filter to find that user document - filter kind of `userName`
*
* Both `.updateMany()` or `.update()` will return write result but not the docs,
* if you need docs in response use `.findOneAndUpdate` or `.findAndModify()`
*/
/** `$` helps to update particular object's caption field in `events` array (Object where `{ 'events._id': eventId }` ) */
await User.updateMany({ 'events._id': eventId },{$set : {'events.$.caption': 'deleted'}}).exec((err)=>{
if (err) throw err;
console.log("status changed saved");
// Redirect back after the job is done.
})
});
Ref : update-documents

Express sends an empty object, but a console.log displays the object correctly [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I'm implementing a simple local auth with express and mongoDB(using mongoose) and for some reason the server sends back an empty response object for user, but the token gets sent in the response. I included a console.log statement immediately before the return to try and debug it a little bit, and the object logged there is the correct one with all of the data. This is what the create code looks like
import mongoose from 'mongoose';
import jwt from 'jsonwebtoken';
import json from '../helpers/json';
var User = mongoose.model('User');
module.exports = function() {
var obj = {};
obj.create = function (req, res) {
var roles = ['authenticated'];
User.count({}, (err, len) => {
if (!len) {
roles.push('admin');
}
var user = new User(req.body);
user.roles = roles;
user.provider = 'local';
user.token = jwt.sign(user, global.config.secret, {expiresIn: 10800});
user.save((err, user) => {
if (err) {
return json.bad(err, res);
}
json.good({
record: user,
token: user.token
}, res);
});
});
};
return obj;
};
Like I said, I had included a console.log statement and the user will display properly.
If you are wondering, the json.good is a helper function that I wrote that basically looks like this
module.exports = {
good: function (obj, res) {
res.send({
success: 1,
res: obj
});
},
bad: function (err, res) {
var obj = {
success: 0,
res: err
};
if (obj.res.errors) {
obj.res.messages = [];
for (var i in obj.res.errors) {
obj.res.messages.push(obj.res.errors[i].message;
}
obj.res.messages = obj.res.messages[0];
}
res.send(obj);
}
};
I am also allowing the correct headers and methods in my express file. This code is identical to code that I have used before, but I am missing something it seems.
Any help would be appreciated, thank you!
!!!!!!! FIXED FIXED FIXED !!!!
I figured out the problem, it was in my model. I had
UserSchema.methods = {
toJSON: function() {
var obj = this.toObject();
delete obj.password;
delete obj.following;
}
};
I had forgotten to return the obj at the end. Thanks everyone!
Make sure that the Value Type in MongoDB matches the Variable type...
So if you have a Key named 'fav' that is an Int32, Then make sure that the variable you use to find it is an Int32.

Mongoose update through $set a value if NOT undefined (NodeJS)

what's the proper way to check for undefined values? What I want to do is to have a PUT method that will update those fields that are not empty. For example, if I send req.body.name = 'John' and no req.body.job I want my request to only change the name.
Some code:
router.put('/:id', (req, res) => {
const query = {_id: req.params.id};
const update = {
$set: {
name: req.body.name,
job: req.body.job
}
};
User.findOneAndUpdate(query, update,
(err, userUpdated) => {
if (err) {
console.log('Error while updating');
console.log(err);
} else {
res.send(userUpdated);
}
});
});
This will of course throw an error:
CastError: Cast to number failed for value "undefined" at path "job"
Now I can manually check if req.body.job is empty and if it is set it's value to the value the user had previously, but that seems like a hack, not elegant and a lot of writing for each route.
I have checked the docs but none of the options provided there seem to do the job. I also came across something like express validator but this will probably just do a return if the value is empty. Another options would be to simply send the value from the front-end part.
I'm new to backend development and I'm not sure if I'm doing stuff the "right way". So please, any comment on how it should be done would be nice (also if my code looks odd, feel free to guide me :)), thanks!
You can write your own method to do this.
For example this example
var req = {body: {name: undefined, job: 'yes'}};
const _ = require('lodash');
const out = {};
_(req.body).forEach((value,key) => {
if (!_.isEmpty(value)){
out[key] = value;
}
});
console.log(out);
Is having this output
{ job: 'yes' }
You can also write it as middleware, if you want, if you write it as this
function onlyNotEmpty(req, res, next) => {
const out = {};
_(req.body).forEach((value, key) => {
if (!_.isEmpty(value)) {
out[key] = value;
}
});
req.bodyNotEmpty = out;
next();
}
Then you can write your method with middleware
router.put('/:id', onlyNotEmpty, (req, res) => {
const query = {_id: req.params.id};
const update = {
$set: req.bodyNotEmpty
};
// This will be the same
});

Resources