Express mongodb find query results empty array - javascript

I'm trying to do an API call to my express server to fetch employees that work in the same place based on the location ID. However, the API call returns just an empty array while it does work in the command-line interface.
Employee model
module.exports = mongoose => {
var schema = mongoose.Schema(
{
first_name: String,
last_name: String,
address: {
housenumber: Number,
street: String,
city: String,
zip: Number,
country: String
},
phone: Number,
mobile: Number,
email: String,
enrollment_date: Date,
staff_id: Number,
location: { type : mongoose.Schema.ObjectId, ref : 'location' },
department: String,
function: String,
active: Boolean
},
{ timestamps: true }
);
schema.method("toJSON", function() {
const { __v, _id, ...object } = this.toObject();
object.id = _id;
return object;
});
const Employee = mongoose.model("employee", schema);
return Employee;
};
Employee routing for API
router.get("/location/:location_id", employees.findAllByLocation);
Employee controller handling above call
exports.findAllByLocation = (req, res) => {
Employee.find({ location: req.params.location_id })
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving Employees."
});
});
};
Dummy database data to test on
Postman API call result
However, trying to find the user with that location ID in the command line interface does work and gives the desired output.
[
So somehow it messes up and I can't seem to figure out why it's doing this. I did some research and found that it might have to do with the location being a reference as an ObjectId. So I tried wrapping the req.params.location_id to an ObjectId might fix it but that didn't work.
What's the best way to get this working?

In order to use promise chain, you have to return something and then returned value will be passed chained “then()” as data. In your example you should
return Employee.find({location:req.params.location_id})

Related

TypeError: Cannot use 'in' operator to search for 'userId'

So i was implementing a users model in my mvc and then i get a weird error saying
MongoClient constructor.
D:\node\node_modules\mongoose\lib\document.js:2022
if (path in this.$__.selected) {
^
TypeError: Cannot use 'in' operator to search for 'email' in saifkhan501721#gmail.com
at model.isSelected (D:\node\node_modules\←[4mmongoose←[24m\lib\document.js:2022:14)
at D:\node\node_modules\←[4mmongoose←[24m\lib\document.js:2195:14
at Array.filter (<anonymous>)
at _getPathsToValidate (D:\node\node_modules\←[4mmongoose←[24m\lib\document.js:2194:71)
at model.Document.$__validate (D:\node\node_modules\←[4mmongoose←[24m\lib\document.js:2365:23)
at D:\node\node_modules\←[4mkareem←[24m\index.js:369:33
←[90m at processTicksAndRejections (internal/process/task_queues.js:79:11)←[39m
i have no idea as to what is the reason behind the error is, is it a syntax error , logical error connection error or mispelling of a variable,well anyway here's my app.js
mongoose
.connect('mongodb+srv://turd_waffle:SaifKhan#cluster0.lltqs.mongodb.net/shop?retryWrites=true&w=majority')
.then((result) => {
User.findOne().then(user=>{
if(!user){
const user=new User({
name:'Saif',
email:'saifkhan501721#gmail.com',
cart:{
items:[]
}
})
user.save()
}
})//save() saves the documents(mostly used as a reference to generate a sample id in order to start a cluster working)
app.listen(3000)
})
.catch(err => {
console.log(err)
})
here's my user.js model to store users data in mongodb database
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
cart: {
items: [{
productId: {
type: Schema.Types.ObjectId,
ref: 'Product',
required: true
},
quantity: {
type: Number,
required: true
}
}]
},
})
userSchema.methods.addToCart = function(product) {
const cartProductIndex = this.cart.items.findIndex(cp => {
return cp.productId.toString() === product._id.toString();
})
let newQuantity = 1;
const updatedCartItems = [...this.cart.items];
if (cartProductIndex >= 0) {
newQuantity = this.cart.items[cartProductIndex].quantity + 1;
updatedCartItems[cartProductIndex].quantity = newQuantity
} else {
updatedCartItems.push({
productId: product._id,
quantity: newQuantity
})
}
const updatedCart = {
items: updatedCartItems
}
this.cart=updatedCart
return this.save()
}
module.exports = mongoose.model('User', userSchema)
can anyone please be kind enough to atleast tell me what the error above is trying to say i used app.use to create a user so i can store his id, email and name
app.use((req, res, next) => {
User.findById('5f788c080ba19e0f8c642202')
.then(user => {
req.user = new User(user.name, user.email, user.cart, user._id);
next();
})
.catch(err => console.log(err));
});
Strange issue. From the code you provided, the issue should not arise.
When I look at the code in mongoose, the only way that this could happen is if you would do something like:
new User("saifkhan501721#gmail.com")
Then this.$__.selected would be a string instead of an object (e.g. {email: "saifkhan501721#gmail.com"}) and path in this.$__.selected would cause your received type error.
Not knowing enough about your app, I would assume that there maybe is a bad User object created somewhere else / cached / or already in database. Maybe it would help to verify this using a clean database?
See the source code for reference. When I take a look at the code it seems like an oversight that it is not checked if this.$__.selected is a string, because in this case it does not fail early (e.g. Object.keys(this.$__.selected) will not cause an error).

find in mongoose returns nothing when there is a non existing field in the schema

I have a mongoose Schema like this:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CitizenSchema = new Schema({
SSN: {
type: Number,
required: true,
unique: true,
},
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
}
});
const Citizen = mongoose.model('Citizen', CitizenSchema);
module.exports = Citizen;
and I have a route in my express app that is like this:
router.get('/', (req, res) => {
if (Object.keys(req.query).length === 0) {
// Get all the citizens if there is no query
Citizen.find({})
.select('-SSN')
.then((citizens) => res.send(citizens));
} else {
const query = req.query;
// Add case insensitive to all queries
for (const q in query) {
query[q] = {
$regex: new RegExp(query[q], 'i')
};
}
Citizen.find(query)
.select('-SSN')
.then((citizens) => res.send(citizens))
.catch((err) => res.status(400).send({ msg: 'Bad query request' }));
}
});
So what I do is that if there is not a query, I return all the citizens and if there is a query, I return the query result.
For example if I send a http request to my route with a GET request like http://localhost:5000/api/citizens/, I get all the citizens. And if I send it with a query like http://localhost:5000/api/citizens/?lastName=Doe&firstName=john, I only get the citizens with the first name as John and last name as Doe.
So my problem is that if I try and do a request like http://localhost:5000/api/citizens/?lastName=Doe&q=test, I get an empty array and not the citizens that have Doe as their last name. The query q makes it so that the Citizen.find() does not work properly and does not return the result that I am waiting for.
I will be appreciate it if someone could help me fix this.
You can try using $or in your queries: https://kb.objectrocket.com/mongo-db/or-in-mongoose-1018

Node JS preventin users from deleting other user's products

I have a REST API built with Node JS and I'm currently using MongoDB as my database. I want to prevent the users from deleting another user's products and for this I checked if the userId from the decoded token is the same as the product userId.
Product schema
const mongoose = require("mongoose");
const productSchema = mongoose.Schema(
{
_id: mongoose.Schema.Types.ObjectId,
userId: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
price: { type: Number, required: true },
productImage: { type: String, required: false },
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
required: true
},
gender: { type: String, required: true }
},
{ timestamps: { createdAt: "created_at" } }
);
module.exports = mongoose.model("Product", productSchema);
The delete product method:
const id = req.params.productId;
Product.findById({ _id: id }).then((product) => {
if (product.userId != req.user._id) {
return res.status(401).json("Not authorized");
} else {
Product.deleteOne({ _id: id })
.exec()
.then(() => {
return res.status(200).json({
message: "Product deleted succesfully",
});
})
.catch((err) => {
console.log(err);
return res.status(500).json({
error: err,
});
});
}
});
};
As you guys see first I'm searching executing the findByID method to access the userId property of the product, then I'm comparing the userId from the response with the userId from the decoded token.
I don't think my method is very efficient since it's running both findById and deleteOne methods.
Can you help me with finding a better solution for this?
as Guy Incognito mentioned, what you are trying to do is an OK thing and you may want to keep it this way in case you want to send a 404 status stating the product they are trying to remove does not exist.
however, if you are trying to do it with only one request
Product.deleteOne({ _id: id, userId: req.user._id })
hope it helps!

How to remove an array element from Mongodb

I'm new to MEAN stack. I'm trying to implement this and this. I'm using $pull. But they ain't working maybe because my structure in mongodb is different from theirs. So let me first show you that:
downvoters is an string array that contains userids who downvoted that particular article. Lets say the person on downvoters[2] i.e 53et853rf later upvoted this article.Then his userid should be removed from downvoters list. Here is my code:
api.js
router.put('/update-upvotes', (req, res) => {
let articleData = req.body;
...
Article.update(
{articleid: '5p4aqbryi'},
{ $pull: { downvoters: '53et853rf' } }
);
Article.findOneAndUpdate(
{articleid: '5p4aqbryi'},
{upvotes: articleData.upvotes, upvoters: articleData.upvoters}, useFindAndModify=false,
(error, user) => {
if(error) {
...
}
else {
...
}
})
})
But that id is not deleted. There's no error or warning on console. Please correct me.
And here is the schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const articleSchema = new Schema({
articleid: String,
title: String,
content: String,
date: String,
contributor: String,
upvotes: Number,
upvoters: [],
downvotes: Number,
downvoters: []
})
module.exports = mongoose.model('article', articleSchema, 'articles');
PS: Let articleId and downvoter id be hardcoded now. I'll make them dynamic later.
Both upvoters and downvoters are String arrays so your Mongoose schema should look like below:
const articleSchema = new Schema({
articleid: String,
title: String,
content: String,
date: String,
contributor: String,
upvotes: Number,
upvoters: [String],
downvotes: Number,
downvoters: [String]
});
You should also keep in mind that update() is an asynchronous operation which needs to be awaited or handled as Promise so:
let opResult = await Article.update(
{articleid: '5p4aqbryi'},
{ $pull: { downvoters: '53et853rf' } }
);
or
Article.update(
{ articleid: '5p4aqbryi' },
{ $pull: { downvoters: '53et853rf' } }
).then(opResult => console.log(opResult));

REST API: PUT but no need all data in json

This is my controller to update put user data. The controller accepts up to 4 values. I would like to do so if I send only a name to this route, This will change only the name and the rest will remain unchanged. (it will not be empty). Is it possible to do this? Do I have to do it in redux-saga, i.e. if it is empty, give it up-to-date
// Update basic User's Data
exports.setUserdata = (req, res) => {
const id = req.params.userId;
User.update(
{
password: req.body.password,
name: req.body.name,
surname: req.body.surname,
email: req.body.email,
},
{ where: { id } },
)
.then(() => {
res.status(200).json({ success: true });
})
.catch(() => {
res.status(500).json({ error: 'Internal server error' });
});
};
Pass params you want to update and don't pass other keys.
If req.body contains only name key, you can just pick up those 4 keys from req.body.
const updateParams = _.pick(req.body, ['name', 'password', 'surname', 'email'])
User.update(updateParams, { where: { id } })
If req.body has other properties with value null or undefined, you can filter them after picking.
const updateParams = _.chain(req.body).pick(['name', 'password', 'surname', 'email']).filter().value()
User.update(updateParams, { where: { id } })
Of course it depends on the ORM you are using but I believe most ORM don't update attributes which are not passed at all.

Categories