Populate in mongoose not working as expected - javascript

This is the model for course and topic, I want to populate topic in course with the help of mongoose. When we call API I want a joint result of course and topic.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let courseSchema = new Schema({
course_id: {
type: Number
},
course_title: {
type: String
},
course_description: {
type: String
},
course_duration:{
type: Number
},
topic:{
type: mongoose.Schema.Types.ObjectId,
ref: "Topic"
}
}, {
collection: "courses"
})
let topicSchema = new Schema({
topic_id: {
type: Number
},
topic_title: {
type: String
},
topic_description: {
type: String
}
}
,{
collection: "topics"
})
const Topic = mongoose.model("Topic", topicSchema)
const Course = mongoose.model('Course', courseSchema)
module.exports = { Topic, Course };
This is API for GET, and I use populate as well but not able to get the joint result of course and topic.
let mongoose = require('mongoose'),
express = require('express'),
router = express.Router();
var { Topic, Course }= require('../models/Course')
router.route('/').get((req, res) => {
Course.find().populate('topic').exec((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
I want output like this:
{
"_id": "5fea9d7cd6651122e04ce5ed",
"course_id": 2,
"course_title": "GOlang",
"course_description": "google ",
"course_duration": 11,
"topic_id": 3,
"topic_title": "hoisting",
"topic_description": "variable and function",
"__v": 0
}

Whay did you do that ? 
router.route('/').get((req, res) => {
Course.find().populate('topic').exec((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
 
 and not this instead ?
   
router.get('/',(req, res) => {
Course.find().populate('topic').exec((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
    

Related

cant add products to shopping cart in mongodb

I am working on a shopping cart and am able to create one in mongodb but I can't add the products that are stored in the DB to the cart. It will just show an empty items array in the console.log as well as mongodb gui. Any help is appreciated.
const express = require('express');
const Carts = require('../repo/carts');
const router = express.Router();
router.post('/cart/products', async (req, res) => {
Carts.findById(req.session.cartId, (err, foundCart) => {
if(err) {
console.log(err)
}
if (foundCart) {
console.log(foundCart);
Carts.update( { _id:req.session.cartId }, {
$push: {
items: {
_id: req.body.productId,
quantity: 1,
},
},
});
} else {
if (!foundCart) {
const newCart = new Carts({
_id: req.session.cartId,
items: [],
});
newCart.save();
}
}
});
res.send('product added to cart!!');
});
module.exports = router;
carts schema for mongodb
const mongoose = require('mongoose');
const cartSchema = new mongoose.Schema({
_id: String,
items: [
{ quantity: Number, _id: String,}
]
});
const Carts = new mongoose.model('Carts', cartSchema);
module.exports = Carts;
image of cart in mongodb robo3t
That err is for the findById, you can add a similar function for the update function and see why it is not working.
Also check if the id body id is received ok.
Carts.findById(req.session.cartId, (err, foundCart) => {
if(err) {
console.log(err) // This err is for the find by Id, not to the update function
}
if (foundCart) {
console.log(foundCart)
console.log(req.body.productId)
Carts.update(
{ _id:foundCart._id }, {
$push: {
items: {
_id: req.body.productId,
quantity: 1,
},
},
},(err,updatedCart) => {
if(err){
console.log(err)
}
}
);
} else {
if (!foundCart) {
const newCart = new Carts({
_id: req.session.cartId,
items: [],
});
newCart.save();
}
}
});
res.send('product added to cart!!');
});
module.exports = router;

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")
}
}

Can't pass multiple documents in an array when using findById

I want to find each of the elements in the array by their id and send it with the post request to create a new post. Right now when I create a new post only passes the first index of the array and if I use find() it passes all of the social schemas regardless if it is in the body of the request. I hope this makes sense if it doesn't please let me know. I hope someone can help.
Below is the mongoose schema for the qrcode post also using Joi
const Joi = require("joi");
const mongoose = require("mongoose");
const { themeSchema } = require("./Theme");
const { userSchema } = require("./User");
const { socialSchema } = require("./Social");
const QrCode = mongoose.model(
"QrCode",
new mongoose.Schema({
user: {
type: userSchema,
required: true,
},
name: {
type: String,
maxLength: 255,
required: true,
trim: true,
},
theme: {
type: themeSchema,
required: true,
},
// Social Media Links
social: [
{
type: socialSchema,
required: true,
},
],
})
);
function ValidateQrCode(qrCode) {
const schema = {
userId: Joi.objectId(),
name: Joi.string().max(255).required(),
themeId: Joi.objectId().required(),
socialId: Joi.array().required(),
};
return Joi.validate(qrCode, schema);
}
module.exports.QrCode = QrCode;
module.exports.validate = ValidateQrCode;
this is the post route to create a new qrcode
router.post("/", auth, async (req, res) => {
const { error } = validate(req.body);
if (error) res.status(400).send(error.details[0].message);
const theme = await Theme.findById(req.body.themeId);
if (!theme) return res.status(400).send("Invalid theme.");
const user = await User.findById(req.user._id);
if (!user) return res.status(400).send("Invalid theme.");
const social = await Social.findById(req.body.socialId);
if (!social) return res.status(400).send("Invalid social.");
const qrCode = new QrCode({
user: user,
name: req.body.name,
theme: theme,
social: social,
});
await qrCode.save();
res.send(qrCode);
});
In the body of my Postman request I am inputting the info below
{
"name": "Friends",
"themeId": "60f89e0c659ff827ddcce384",
"socialId": [
"60f89e43659ff827ddcce386",
"60f89e5c659ff827ddcce388"
]
}
To fetch data using ids, you can use below mongodb query simply,
db.collection.find( { _id : { $in : ["1", "2"] } } );
In mongoose,
model.find({
'_id': { $in: [
mongoose.Types.ObjectId('1'),
mongoose.Types.ObjectId('2'),
mongoose.Types.ObjectId('3')
]}
}, function(err, docs){
console.log(docs);
});
Or
await Model.find({ '_id': { $in: ids } });

Check if ID exist in related mongodb collection with mongoose

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);
}
};

Mongoose populate array is empty

I have defined a UserSchema and a PostSchema in my model.js. UserSchema has a ref to its own Posts, while PostSchema has a ref to its author.
In my controllers.js methods I'm creating a user and a post instance (bound to the newly created user). I'm now trying to populate the user's posts, but mongoose returns an empty array. However, the other way around works (I'm able to retrieve the user by a Post instance).
models.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: String,
posts: [{
type: Schema.Types.ObjectId,
ref: 'Post'
}]
})
const PostSchema = new Schema({
content: String,
author: {
type: Schema.Types.ObjectId,
ref: 'User'
}
})
const Post = mongoose.model('Post', PostSchema, 'posts');
const User = mongoose.model('User', UserSchema, 'users');
module.exports = { Post, User }
controllers.js
require('../model/db'); // DB config
const mongoose = require('mongoose');
const models = require('../model/models');
const getUser = (req, res) => {
const user = new models.User({
_id: new mongoose.Types.ObjectId(),
username: 'JohnDoe'
});
user.save(function (err) {
if (err) return res.json(err);
const post = new models.Post({
content: 'New Post',
author: user.id
});
post.save(function (err) {
if (err) return res.json(err);
models.User.findOne({
username: 'JohnDoe'
})
.populate('posts').exec((err, user) => {
res.json(user);
})
});
});
}
const getPost = (req, res) => {
const user = new models.User({
_id: new mongoose.Types.ObjectId(),
username: 'JohnDoe'
});
user.save(function (err, user) {
if (err) return res.json(err);
const post = new models.Post({
content: 'NewPost',
author: user.id
});
post.save(function (err, post) {
if (err) return res.json(err);
models.Post.findOne({
content: 'NewPost'
})
.populate({
path: 'author',
model: 'User'
}).exec((err, user) => {
res.json(user);
})
});
});
}
getUser's result (posts is empty):
{
"posts": [],
"_id": "5b9426a6fd187d3949470f54",
"username": "JohnDoe",
"__v": 0
}
getPost result (author is correctly returned)
{
"_id": "5b94287e99072c3a173419f2",
"content": "NewPost",
"author": {
"posts": [],
"_id": "5b94287e99072c3a173419f0",
"username": "JohnDoe",
"__v": 0
},
"__v": 0
}
You need to push the post id to the posts array in the user model as follows
const getUser = (req, res) => {
const newUser = new models.User({ username: 'JohnDoe' });
newUser.save(user => {
if (err) return res.json(err);
const newPost = new models.Post({
content: 'New Post',
author: user._id
});
newPost.save(post => {
if (err) return res.json(err);
models.User.findByIdAndUpdate(user._id,
{ '$push': { 'posts': post._id } },
{ 'new': true }
)
.populate('posts')
.exec((err, u) => {
res.json(u);
})
});
});
}
Using async/await
const getUser = async (req, res) => {
try {
const newUser = new models.User({ username: 'JohnDoe' });
const user = await newUser.save();
const newPost = new models.Post({
content: 'New Post',
author: user._id
});
const post = await newPost.save();
const result = await models.User.findByIdAndUpdate(user._id,
{ '$push': { 'posts': post._id } },
{ 'new': true }
)
.populate('posts')
.exec();
res.json(result)
}
catch (err) {
return res.json(err);
}
}

Categories

Resources