Check if ID exist in related mongodb collection with mongoose - javascript

I have a "Drinkers" model and a "Sodas" model which is "related" - a drinker can have drunk X amount of sodas.
The route to get the data is this
router.get('/all/:drinkerId', sodasController.getAllSodasFromDrinker)
In my sodasController, is there a way to check if :drinkerId exists in the "Drinkers" collection and if not return an error that the drinker doesn't exist, without having to require the drinkersController in the sodasController.
Right now getAllSodasFromDrinker looks like this
const Sodas = require("../models/sodas.model");
exports.getAllSodasFromDrinker = async (req, res, next) => {
try {
const id = req.params.drinkerId;
if (id.match(/^[0-9a-fA-F]{24}$/)) {
await Sodas.find({ drinker: id }).exec((err, drinkerItem) => {
if (err) {
return next(err);
}
res.json({ data: drinkerItem });
});
} else {
return next("ID is in the wrong format");
}
} catch (error) {
return next(error);
}
};
In that function, I want to check if a user exists with the applied ID.
I want to avoid having to
const Drinkers = require("../models/drinkers.model") in the sodasController
The Drinkers model:
const Schema = mongoose.Schema;
const drinkersSchema = new Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
sodas: {
type: Schema.Types.ObjectId,
ref: "Sodas",
},
},
{ timestamps: true }
);
The Sodas model
const Schema = mongoose.Schema;
const sodaSchema = new Schema(
{
name: {
type: String,
required: true,
},
drinker: {
type: Schema.Types.ObjectId,
ref: "Drinkers",
},
},
{ timestamps: true }
);

I would add a middleware function which validates if the drinkerId exists. If it exists, you can continue to the controller. If not, then you should throw a 404 error.
Your route:
router.get(
'/all/:drinkerId',
drinkerMiddleware.exists,
sodasController.getAllSodasFromDrinker
);
drinkerMiddleware:
exports.exists = async (req, res, next) => {
try {
const drinker await Drinker.find({ drinker: req.params.drinkerId }).exec();
if (!drinker) {
return next("Drinker not found.");
}
return next();
} catch (error) {
return next(error);
}
};

Related

variable value is not changing in a map function paired with mongoose querys

i am working on a mern project where i need to create an agenda that contains an attribute as array of appointments types.
in the nodejs api i am declaring a var typeRefs = [];
if a type is present in the types model i insert its ref in the previous array else i create the type and insert the new type ref in the previous array, finally i create the agenda doc based on the typeRefs array, but the array is empty outside the map function scope , inside the map function scope i can see the array values changing.
//agenda model
const agendaSchema = mongoose.Schema(
{
name: String,
types: [{ type: mongoose.Schema.Types.ObjectId, ref: "Type" }],
establishment: {
type: mongoose.Schema.Types.ObjectId,
ref: "Establishment",
},
template: { type: mongoose.Schema.Types.ObjectId, ref: "Template" },
isActive: { type: Boolean, default: true },
},
{ timestamps: true }
);
var Agenda = mongoose.model("Agenda", agendaSchema);
export default Agenda;
// types model
import mongoose from "mongoose";
const typeSchema = mongoose.Schema(
{
name: String,
duration: Number,
color: String,
online: { type: Boolean, default: true },
establishment: {
type: mongoose.Schema.Types.ObjectId,
ref: "Establishment",
},
},
{ timestamps: true }
);
var Type = mongoose.model("Type", typeSchema);
export default Type;
// api function for agenda creation
export const add = async (req, res) => {
var data = req.body;
try {
var typesRefs = [];
data.types.map((type) => {
Type.find({ name: type.text.toUpperCase() }, (err, res) => {
if (res.length === 0) {
const newType = new Type({
name: type.text.toUpperCase(),
establishment: data.establishment,
});
newType.save();
typesRefs = [...typesRefs, newType._id];
} else {
typesRefs = [...typesRefs, type._id];
}
});
});
console.log(typesRefs);
await Agenda.create({ ...data, types: typesRefs });
res.status(200).json({ message: "Agenda created successfully" });
} catch (error) {
console.log(error);
res.status(401).json({ message: "An error occured !" });
}
};
the trick is to use a for loop instead of map function.
export const add = async (req, res) => {
var data = req.body;
var typeRefs = [];
try {
for (let i = 0; i < data.types.length; i++) {
const typeExist = await Type.find({
name: data.types[i].text.toUpperCase(),
});
if (typeExist.length === 0) {
const newType = await Type.create({
name: data.types[i].text.toUpperCase(),
establishment: data.establishment,
});
typeRefs = [...typeRefs, newType._id];
} else {
typeRefs = [...typeRefs, data.types[i]._id];
}
}
console.log(typeRefs);
await Agenda.create({ ...data, types: typeRefs });
res.status(200).json({ message: "Agenda created successfully" });
} catch (error) {
console.log(error);
res.status(401).json({ message: "An error occured !" });
}
};

Cannot read properties of null (reading 'experience'). after all this i should get profile with all experience .but all time i end up with server err

i was following brad traversy's one of his udemy course. after working on adding experience in profile in profile routes. i all time get server error. but it should end up with full profile details like in brad course. this is my github link for that project
https://github.com/arshad007hossain/findDevs
profile.js
const express = require("express");
const router = express.Router();
const auth = require("../../middleware/authmiddleware");
const { check, validationResult } = require("express-validator");
const Profile = require("../../models/Profile");
const User = require("../../models/User");
// #route GET api/profile/me
// #desc Get current users profile
// #access Private
router.get("/me", auth, async (req, res) => {
try {
const profile = await Profile.findOne({
user: req.user.id,
}).populate("user", ["name", "avatar"]);
if (!profile) {
return res.status(400).json({ msg: "There is no profile for this user" });
}
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
});
// #route POST api/profile/me
// #desc create or update users profile
// #access Private
router.post(
"/",
[
auth,
[
check("status", "status is required").not().isEmpty(),
check("skills", "skills is required").not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubusername,
facebook,
linkedin,
twitter,
instagram,
youtube,
skills,
} = req.body;
//build user profile
const profileFields = {};
profileFields.user = req.user.id;
if (company) profileFields.company = company;
if (website) profileFields.website = website;
if (location) profileFields.location = location;
if (bio) profileFields.bio = bio;
if (status) profileFields.status = company;
if (githubusername) profileFields.githubusername = githubusername;
if (skills) {
profileFields.skills = skills.split(",").map((skill) => skill.trim());
}
//build social objects
profileFields.social = {};
if (youtube) profileFields.social.youtube = youtube;
if (twitter) profileFields.social.twitter = twitter;
if (linkedin) profileFields.social.linkedin = linkedin;
if (instagram) profileFields.social.instagram = instagram;
if (facebook) profileFields.social.facebook = facebook;
//console.log(profileFields.skills);
try {
let profile = await Profile.findOne({ user: req.user.id });
if (profile) {
//Update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
);
return res.json(profile);
}
//create
profile = new Profile(profileFields);
await profile.save();
res.json(profile);
} catch (err) {
console.errora(err.message);
res.status(500).json("server error");
}
}
);
// #route GET api/profile
// #desc Get all profile
// #access Public
router.get("/", async (req, res) => {
try {
let profiles = await Profile.find().populate("user", ["name", "avatar"]);
res.json(profiles);
} catch (err) {
console.error(err.message);
res.status(500).json("server error");
}
});
// #route GET api/profile/user/user_id
// #desc Get single profile
// #access Public
router.get("/user/:user_id", async (req, res) => {
try {
const profile = await Profile.findOne({
user: req.params.user_id,
}).populate("user", ["name", "avatar"]);
if (!profile) return res.status(400).json({ msg: "Profile not found" });
res.json(profile);
} catch (err) {
if (err.kind == "ObjectId") {
return res.status(400).json({ msg: "Profile not found" });
}
console.error(err.message);
res.status(500).json("server error");
}
});
// #route DELETE api/profile
// #desc Delete profile, user
// #access Private
router.delete("/", auth, async (req, res) => {
try {
// Remove profile
await Profile.findOneAndRemove({ user: req.user.id });
// Remove user
await User.findOneAndRemove({ _id: req.user.id });
res.json({ msg: "User deleted" });
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
});
// #route PUT api/profile/experience
// #desc Add profile experience
// #access Private
router.put(
'/experience',
[
auth,
[
check('title', 'Title is required field').not().isEmpty(),
check('company', 'Company is required field').not().isEmpty(),
check('from', 'From date is required field').not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
title,
company,
location,
from,
to,
current,
description,
} = req.body;
const newExp = {
title,
company,
location,
from,
to,
current,
description,
};
try {
const profile = await Profile.findOne({ user: req.user.id });
profile.experience.unshift(newExp);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
module.exports = router;
User.js
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
avatar: {
type: String,
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = User = mongoose.model("user", UserSchema);
Profile.js Model
const mongoose = require('mongoose');
const ProfileSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
company: {
type: String
},
website: {
type: String
},
location: {
type: String
},
status: {
type: String,
required: true
},
skills: {
type: [String],
required: true
},
bio: {
type: String
},
githubusername: {
type: String
},
experience: [
{
title: {
type: String,
required: true
},
company: {
type: String,
required: true
},
location: {
type: String
},
from: {
type: Date,
required: true
},
to: {
type: Date
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
education: [
{
school: {
type: String,
required: true
},
degree: {
type: String,
required: true
},
fieldofstudy: {
type: String,
required: true
},
from: {
type: Date,
required: true
},
to: {
type: Date
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
social: {
youtube: {
type: String
},
twitter: {
type: String
},
facebook: {
type: String
},
linkedin: {
type: String
},
instagram: {
type: String
}
},
date: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('profile', ProfileSchema);

._doc in Mongoose

I have this js code
app.post('/auth', async (req, res) => {
try {
const user = UserModel.findOne({email: req.body.email}).exec()
if (!user) return res.status(404).json({
message: 'Not find user'
})
const isValidPassword = bcrypt.compare(req.body.password,user._doc.passwordHash)
if (!isValidPassword) return res.status(404).json({
message: 'Incorrect password'
})
}
catch (err) {
console.log(err)
res.status(500).json({
message: 'error'
})
}
})
And I have this Schema
import mongoose from 'mongoose'
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
passwordHash: {
type: String,
required: true
},
telegramUrl: {
type: String,
required: true
},
avatarUrl: String
},
{
timestamps: true
}
)
export default mongoose.model('User', userSchema)
In this line
const isValidPassword = bcrypt.compare(req.body.password,user._doc.passwordHash)
I have error: Cannot read properties of undefined (reading 'passwordHash'). Why am I getting an error? He writes to me that ._doc undefined but why? Help me please
use these two methods in your schema
const bcrypt = require("bcrypt");
// Create Hash Salt Password ..
userSchema.pre("save", async function (next) {
if (!this.isModified("passwordHash")) return next();
this.passwordHash = await bcrypt.hash(this.passwordHash, 12);
next();
});
// Compare Password ...
userSchema.methods.comparePassword = function (passwordHash) {
return bcrypt.compareSync(passwordHash, this.passwordHash);
};
And in your auth code
app.post('/auth', async (req, res) => {
try {
const user = await UserModel.findOne({email: req.body.email}).exec()
if (user) {
res.status(400).json(
{ message: 'User already register'})
}
else{
const newuser = New User({
name: req.body.name,
// also write other schema fields
}
const res = await newuser.save();
console.log(res)
catch (err) {
console.log(err)
res.status(500).json({
message: 'error'
})
}
})
I hope this should resolve your problem

How does a function writer call the getByName . function

books-controllers
I want the data to appear by the name in the postman and not the ID because I have information and I want to fetch it through the name in the database
const getByName = async (req, res, next) => {
const name = req.params.name;
let book;
try {
book = await Book.getByName("name");
} catch (err) {
console.log(err);
}
if (!book)
return res.status(404).json({ message: "No book found" });
}
return res.status(200).json({ book });
};
modelSchema
Here is the Skyma model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const bookSchema = new Schema({
name: {
type: String,
require: true
},
description: {
type: String,
require: true
},
price: {
type: Number,
require: true
},
avilable: {
type: Boolean,
},
image: {
type: String,
require: true
},
});
module.exports = mongoose.model("Book", bookSchema);
There in no in-built method in mongoose getByName. You can use generic find to search for object using name
let book = await Book.find({ name: name }).exec();
You can also use findOne if needed.
You can try this -
async function getByName(req, res){
const bookname = req.params.name ;
try {
const book = await Book.findOne({name: bookname})
if(book!==null) {
res.status(200).send({'data': book}) ;
}
else {
res.status(404).send("No book found !")
}
}
catch(error) {
console.log(error)
res.send("Error")
}
}

Api call finds already deleted documents

I've two endpoints: one that delete product document and one that retrieve the document.
After I delete the document throught by Id, the GET api call return me already the document even if it's deleted and It's not present on MongoDb.
Response of DELETE call returns { deletedCount: 1 }
Here code of GET product:
exports.getSingleProduct = (req, res, next) => {
let id = req.params.id;
Products.findById(id).populate({ path: 'internalColor' }).then(result => {
if(result && result.visible == true) {
res.status(200).json(result)
} else {
res.status(404).json({
message: 'product_not_found',
id: id
})
}
}).catch(err => {
res.status(404).json({
message: 'error_operation: ' + err,
id: id
})
});
}
Here code of DELETE product:
exports.deleteDefinallySingleProduct = (req, res, next) => {
let id = req.params.id;
console.log(id)
Products.deleteOne({ id: id }).then(result => {
if(result) {
res.status(200).json({
message: 'deleted_product'
});
}
}).catch(err => {
res.status(404).json({
message: 'error_operation: ' + err
})
})
}
Products Model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const options = {
timestamps: true
}
const productSchema = new Schema({
name: {
type: String,
required: true
},
description: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
externalUrl: {
type: String,
required: true
},
imgUrl: {
type: String,
required: true
},
brand: {
type: String,
required: true
},
visible: {
type: Boolean,
required: true
}
}, options);
const Product = mongoose.model('Products', productSchema);
module.exports = Product;
I think the error that you are facing is caused by a typo in your code.
exports.deleteDefinallySingleProduct = (req, res, next) => {
...
Products.deleteOne({ id: id }).then(result => {
if(result) {
// this code will run always
console.log(result) // will show { n: 0, ok: 1, deletedCount: 0 },
// That is, this section of code will run always despite of delete count being 0 or more due to the request to be excecuted successfully.
...
}
The correct implementation is here:
exports.deleteDefinallySingleProduct = (req, res, next) => {
...
Products.deleteOne({ _id: id }).then(result => {
...
}
This is because by default mongooose use _id representing the document id, unless create a custom id in the schema which you didn't do.

Categories

Resources