how to fetch user details from populated table in nodejs? - node.js

I have two tables in my MongoDB cluster i.e Post and User. Actually I want to retrieve the username and userID along with a post from the post table when a user posts something.
my post controller
router.getPostsList = async (req, res) => {
try {
const posts = await Post.list();
return res.status(200).json(posts);
} catch (err) {
return res.status(400).json(err);
}
};
MongoDB Post collection Image
PostSchema
const PostSchema = new mongoose.Schema(
{
text: {
type: String,
trim: true
},
slug: {
type: String,
trim: true,
lowercase: true
},
user: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
]
},
{ timestamps: true }
);

Related

Moongoose populate method returning an empty array

I am trying to fetch the blogs that a user has posted using mongoose populate method but not able to do so but when I try to look for the user who posted a blog I am able to do so. Tell me what I am doing wrong.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema({
username: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
blogPosts: [{ type: mongoose.Types.ObjectId, ref: "Blogs", required: true }],
});
const Users = mongoose.model("Users", userSchema);
module.exports = Users;
This is my user model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const blogSchema = new Schema({
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
image: {
type: String,
required: true,
},
user: {
type: mongoose.Types.ObjectId,
ref: "Users",
required: true,
},
});
const blogs = mongoose.model("Blogs", blogSchema);
module.exports = { blogs, blogSchema };
this is my blogs model
router.get("/users/:id", async (req, res) => {
let userBlogs;
try {
userBlogs = await users.find({ _id: req.params.id }).populate("blogPosts");
if (!userBlogs) {
return res.status(404).json({ msg: "No user found" });
}
return res.status(200).json(userBlogs);
} catch (err) {
return res.status(500).json({ err });
}
});
this is the route that I use for fetching all the blogs that a user has posted.This is just sending me back an empty posts array.
router.post("/newBlog/:id", async (req, res) => {
let blogAuthor;
try {
blogAuthor = await users.findOne({ _id: req.params.id });
} catch (err) {
return res.status(404).json({ message: "user not found" });
}
const newBlog = blogs({
title: req.body.title,
description: req.body.description,
image: req.body.imageUrl,
user: blogAuthor._id,
});
try {
await blogAuthor.blogPosts.push(newBlog);
await newBlog.save();
return res.status(200).json(blogAuthor.blogPosts);
} catch (err) {
return res.status(500).json(err);
}
});
the above is the route that I use to add new blog to the db.
router.get("/allBlogs", async (req, res) => {
let allBlogs;
try {
allBlogs = await blogs.find({}).populate("user");
} catch (err) {
return res.status(404).json(err);
}
res.status(200).json(allBlogs);
});
this is the route that sends all the blogs posted by all the users.
Interesting thing is that when I try to populate the user of a blogpost that is working exactly as expected it is populating the user of the blog from the users model however when I try to do the reverse that's not working. It is not populating all the blogs that a user has posted.

Router.post an array of Object ID'S using Mongoose and NodeJs router.post

I almost have the desired functionality but it's not exactly what I wanted to approach.
I have two model schema, Control and SubControl. The SubControl is referenced in the Control model. I want to post the control model + a reference of the SubControl.
My post method:
router.post(
'/add',
auth,
role.checkRole(role.ROLES.Admin, role.ROLES.Regulator),
async (req, res) => {
try {
const subControl = new SubControl({...req.body});
const subControlDoc = await subControl.save();
const control = new Control({...req.body});
control.subControl.push(subControlDoc._id);
const savedControl = await control.save();
res.status(200).json({
success: true,
message: `Control has been added successfully!`,
control: savedControl
});
} catch (error) {
return res.status(400).json({
error
// error: 'Your request could not be processed. Please try again.'
});
}
}
);
My Control Schema:
const ControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
mainControl: {
type: String
},
subControl: [{
subControlNo: {type: Mongoose.Schema.Types.String, ref: 'SubControl'}
}],
controlDescription: {
type: String,
trim: true
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('Control', ControlSchema);
My SubControl schema:
const SubControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
subControlNo: {
type: String
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('SubControl', SubControlSchema);
Postman:
{
"mainControl": "nn",
"controlDescription": "controldescription",
"subControl":
[
{
"subControlNo": "1-2"
},
{
"subControlNo": "1-2-1"
}
]
}
Result I'm getting:
Question: Why am I getting 3 object id's although I inserted 2 and why only the last object ID is saved in my SubControl database? I this the way to add array of object id's or not?

How to save data in mongodb express by referring another document

I have created the following User schema
const UserSchema = mongoose.Schema(
{
fullName: {
type: String,
required: true,
index: true,
},
department: {
type: mongoose.Schema.Types.ObjectId,
ref: "Department",
required: true,
},
},
});
and my Department schema looks like the following
const DepartmentSchema = mongoose.Schema(
{
name: {
type: String,
unique: true,
required: true,
},
description: {
desc: "Description.",
type: String,
},
},
{
strict: true,
versionKey: false,
timestamps: { createdAt: "createdAt", updatedAt: "updatedAt" },
});
Now I'm able to create departments and all is working well in Postman and also my Angular application. But while creating User it only saves the department ID that I've selected or added in my form. This is the data that I've tried to create
user = {
department: "5f806be7c9a3c02c7c61f9f1"
fullName: "John Joshua"
}
and my create route controller looks like this
exports.create = async (req, res) => {
const newUser = new User({
fullName: req.body.fullName,
department: req.body.department,
});
try {
const errors = validationResult(req); // I've used express validator here
if (!errors.isEmpty()) {
res.status(400).json({ errors: errors.array() });
return;
}
const savedUser = await newUser.save();
res.json(savedUser); // Here I was expecting to return the new saved user with Department details
} catch (err) {
res.status(500).json({ message: err });
}
};
So my response is all good and working well but department only contains the ID with nothing more.
How can I send a response data with Department details? Any help is appreciated.

dynamic references by sending it from the route

I have been looking at the documentation and some other questions made, but I have not been able to do it, I need to consult another collection for an objectId, but these collections come dynamically in the routes.
The collections come req, as they are from many different clients
https://mongoosejs.com/docs/populate.html
//route
// example collection dynamic ssdf2451_users, ssdf2451_campus, ssdf2451_programs
router.get('/school/prueba/tipos/', async (req, res, next) => {
let users
let school
let prueba
try {
const Users = model(`ssdf2451_users`, UserSchema)
console.log(Users)
await Users.findOne({ _id: '5ef56f70d19aea6e70c82a50' })
.populate('schoolId')
.exec(function (err, usersDocuments) {
console.log(usersDocuments, err)
// handle err
prueba = usersDocuments
res.status(200).json(prueba)
})
} catch (err) {
next(err)
}
})
// Schema
import { Schema, model } from 'mongoose'
const UserSchema = new Schema({
state: {
type: Boolean,
default: false,
required: false
},
accountNumber: {
type: Number,
required: false
},
schoolId: {
type: Schema.Types.ObjectID,
required: true,
ref: 'schools'
},
campusId: {
type: Schema.Types.ObjectID,
required: true,
ref: dynamic
},
programsId: {
type: [Schema.Types.ObjectID],
required: false,
ref: dynamic
},
})
const User = model('users', UserSchema)
export { User, UserSchema }

How can I query an Array for a subdocument with mongoose?

I am looking to query a subdocument that contains an array.
You can think of this as an application similar to medium.com or tumblr.com:
I have a user schema, and User's have many Posts. My post schema has a 'tags' key which is an array I am trying to create a route which will display all posts that have a certain tag.
So for instance,
GET /user/posts/:tag
GET /user/posts/dogs
might return back the data for all posts (by any user) that have the tag 'dogs'
{
description: 'dogs are cool',
title: 'huskies',
tags: ['dogs','animals','outdoors'],
original_poster: '34255352426'
},{
description: 'My puppies are nice',
title: 'Puppies',
tags: ['pugs','dogs','small'],
original_poster: '44388342426'
},{
description: 'I like cats more than dogs',
title: 'Cats',
tags: ['kittens','cats','dogs'],
original_poster: '15708213454'
}
Here is my User Schema:
const mongoose = require('mongoose'),
Schema = mongoose.Schema,
PostSchema = require('./post-model.js');
let UserSchema = new Schema({
email: {
type: String,
required: true,
unique: true
},
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: false, //only required for local users
unique: false,
default: null
},
following: {
type: [Number],
required: false,
unique: false
},
followers: {
type: [Number],
required: false,
unique: false
},
posts: [PostSchema],
})
module.exports = mongoose.model('User',UserSchema);
Here is my Post Schema:
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
let PostSchema = new Schema({
description: {
type: String,
required: false,
unique: false
},
title: {
type: String,
required: false,
unique: false
},
tags: {
type: [String],
required: true
},
original_poster: {
type: String,
required: true
}
});
module.exports = PostSchema;
EDIT:
to clarify my question, imagine that this was a regular js object, here is what a function to return all data relevant to a specific tag:
let users = [];
let user1 = {
username: 'bob',
posts: [
{
title: 'dogs r cool',
tags: ['cats','dogs']
},
{
title: 'twd is cool',
tags: ['amc','twd']
}]
};
let user2 = {
username: 'joe',
posts: [{
title: 'mongodb is a database system that can be used with node.js',
tags: ['programming','code']
},
{
title: 'twd is a nice show',
tags: ['zombies','horror-tv','amc']
},
{
title: 'huskies are my favorite dogs',
tags: ['huskies','dogs']
}]
}
users.push(user1);
users.push(user2);
function returnPostByTag(tag) {
let returnedPosts = [];
users.forEach((user,i) => {
user.posts.forEach((post) => {
if(post.tags.includes(tag)) {
let includespost = {}
includespost.title = post.title;
includespost.tags = post.tags;
includespost.original_poster = user.username;
returnedPosts.push(includespost);
}
})
})
return returnedPosts;
}
If you want to see a full repl where I use a plain js example here it is: https://repl.it/repls/LavenderHugeFireant
You can do the following using Mongoose to return all users where the tags array in any of the subdocuments in the posts array includes tag:
User.find({ 'posts.tags': tag }, function(err, users) {
if (err) {
// Handle error
}
let filteredPosts = users
.map(user => {
user.posts.forEach(post => post.original_poster = user.username)
return user
})
.map(user => user.posts)
.reduce((acc, cur) => acc.concat(cur), [])
.filter(post => post.tags.includes(tag))
// Do something with filteredPosts
// ...such as sending in your route response
})
...where User is your Mongoose model and tag contains the tag string you want to query (perhaps from your route request).
If you are using promises then you could do:
User.find({ 'posts.tags': tag })
.then(users => {
let filteredPosts = users
.map(user => {
user.posts.forEach(post => post.original_poster = user.username)
return user
})
.map(user => user.posts)
.reduce((acc, cur) => acc.concat(cur), [])
.filter(post => post.tags.includes(tag))
// Do something with filteredPosts
// ...such as sending in your route response
})
.catch(err => {
// Handle error
})

Resources