NodeJS/Mongoose: Cast to ObjectId failed for value "..." at path "_id" - node.js

On the main page, there is a hyperlink with profile/5aa3cfb783622a145a86d616 that points to the profile page of a user, where 5aa3cfb783622a145a86d616 is the Object ID of the user (it is shown as "_id" : ObjectId("5aa3cfb783622a145a86d616") in MongoDB).
When I click on the link, the page fully loads without any problem. However, the terminal still says Cast to ObjectId failed for value "..." at path "_id" for model "User", and the browser's favicon still shows that it is loading, even though the page has fully loaded.
I tried searching for answers, but none of them are specific to my problem.
EDIT
After playing with the code, I found that the problem seems to lie in the multiple "populate" methods, which I have previously ignored when simplifying the questions, as I thought there was no issue with it. I now include the full code below.
Inside the User document, there is a Post array containing the Post's ID. Each post document has Author, Likes, and Comment. In the Comment array, each comment document has the Author's ID. All of these have to be populated.
NodeJS/Mongoose:
router.get("/:id", function(req, res){
User.findById(req.params.id).populate({
path: 'posts',
populate: [{
path: 'author',
},
{
path: 'likes',
},
{
path: 'comments',
populate: [{
path: 'author'
}]
}]
})
.exec(function(err, user){
console.log(user);
res.render("profile", {user: user});
});
});
User Schema
var UserSchema = new mongoose.Schema({
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Post"
}
]
});
Post Schema
var postSchema = mongoose.Schema({
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
],
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});
Comment Schema
var commentSchema = mongoose.Schema({
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
});
When I console.log(user), the terminal returns the following. I'm not too sure why it shows author[object] instead of its actual ID, maybe this is the problem?
{ posts:
[ { likes: [],
comments: [],
_id: 5aa3d0d806711d1483ae7e3e,
__v: 0,
author: [Object] },
{ likes: [],
comments: [],
_id: 5aa3cfc483622a145a86d618,
__v: 0,
author: [Object] },
{ likes: [],
comments: [],
_id: 5aa3cfbe83622a145a86d617,
__v: 0,
author: [Object] } ],
__v: 3}
EDIT 2
Weird enough, my other route which has the same structure (except its friendPosts) is working without any issue.
router.get("/home", function(req, res){
User
.findById(req.user._id)
.populate({
path: 'friendPosts',
populate: [{
path: 'author',
},
{
path: 'likes',
},
{
path: 'comments',
populate: [{
path: 'author'
}]
}]
})
.exec(function(err, currentUser){
res.render("main/home", {user: currentUser});
});
});

You need to try this:
const { ObjectId } = require('mongoose').Types;
router.get("/:id", function(req, res) {
const { id } = req.params;
User.findOne({ id: ObjectId(id)}).populate({
path: 'posts',
populate: [{
path: 'author',
},
{
path: 'likes',
},
{
path: 'comments',
populate: [{
path: 'author'
}]
}
]
}).exec(function(err, user) {
console.log(user);
res.render("profile");
});
});

Related

How to populate nested model in mongoose

I have dataSubmitted model:
module.exports = (mongoose, mongoosePaginate) => {
const schema = mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
company: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
}, {
timestamps: true
})
schema.plugin(mongoosePaginate)
const dataSubmitted = mongoose.model('dataSubmitted', schema)
return dataSubmitted
}
And i have the other model is called "profile" for user profile. I use user._id to releation with "profile" model.
My profile model:
module.exports = (mongoose, mongoosePaginate) => {
const schema = mongoose.Schema({
name: String,
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
}, {
timestamps: true
})
schema.plugin(mongoosePaginate)
const profile = mongoose.model('profile', schema)
return profile
}
The result json from select dataSubmitted, is like this:
totalItems": 90,
"data": [
{
"_id": "63546cb05bfb8607c005da6a",
"user": "6353a1aebaf28d7aa066a963",
"company": "6022487bbe148f3a9b132122",
"createdAt": "2022-10-22T22:20:32.296Z",
"updatedAt": "2022-10-25T07:09:52.363Z",
"__v": 0
},
]
My question is how can i populate the user id with "profile" model?
My current code:
const options = {
populate: [
{
path: 'user',
populate: {
path: 'user',
model: 'profile'
}
}
],
sort: ({ createdAt: -1 })
}
but its return "user": null if i add nested populate like that.
If you need to reference the profile model from the dataSubmitted you should change your schema declaration to:
const dataSubmittedSchema = mongoose.Schema(
{
profile: {
type: mongoose.Schema.Types.ObjectId,
ref: 'profile',
},
company: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
},
{
timestamps: true,
}
);
Then, you should be able to populate with:
dataSubmitted.find({}).populate({
path: 'profile',
populate: {
path: 'user'
}
})

mongoose aggregation not returning expected result

I am currently learning aggregation and some related methods, after following mongoose and mongodb docs i tried it. but i am having problem.
Follow.aggregate([
{ $match: { user: mongoose.Types.ObjectId(userId) } },
{ $unwind: '$followers' },
{
$lookup: {
from: 'accounts',
localField: 'followers',
foreignField: '_id',
as: 'followers'
}
},
{ $project: { name: 1, photo: 1 } },
]).exec((err, followers) => {
if (err) throw err;
console.log(followers);
res.send(followers);
});
I want to get the followers of that userID and select the followers names and photo, but i am only getting the objectid of the matched document
[ { _id: 5bfe2c529419a560fb3e92eb } ]
expected output
[ { _id: 5bfe2c529419a560fb3e92eb , name: 'john doe", photo: 'cat.jpg'} ]
Follow Model
const FollowSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'Account',
required: true,
},
following: [{
type: Schema.Types.ObjectId,
ref: 'Account',
required: true,
}],
followers: [{
type: Schema.Types.ObjectId,
ref: 'Account',
required: true,
}],
});
When the $project stage is wrong you would get that result. Try removing it first and see the output. To me it seems you should have something like this there:
{ $project: { "followers.name": 1, "followers.photo": 1 } },

mongoose .populate not working

I'm using nodejs/express and mongoose. However, when trying to use .populate(...) on a document it doesn't work. Here is my code:
I have this schema for a User:
const UserSchema = new Schema({
...
friends: [{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
...
}],
sentRequests: [{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
...
}],
recievedRequests: [{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
...
}]
}
mongoose.model('users', UserSchema);
Then when I try to show all the recievedRequests to a page I use this code:
router.get('/friendRequests', (req, res) => {
User.findOne({
_id: req.user.id // where req.user is the currently logged in user
})
.populate('recievedRequests.user')
.then(curUser => {
res.render('friends/friendRequests', {
curUser: curUser
});
})
});
where User is the model and req.user.id is the id of the currently logged in user. However, in the webpage whenever I reference curUser.recievedRequests.user it simply returns the id of the user and not the actual user object. Does anyone know what I might be doing wrong here?
Thanks.
EDIT - Example
For a document:
user1 = {
_id: ObjectId("5ae94b0b2bb9383d4029d64b"),
...
recievedRequests: [
{"_id" : ObjectId("5ae94b5f29c86c4a343d2d0a") }
]
}
and
user2 = {
_id: ObjectId("5ae94b5f29c86c4a343d2d0a"),
...
}
Using my above code on this document:
router.get('/friendRequests', (req, res) => {
User.findOne({
_id: user1.id
})
.populate('recievedRequests.user')
.then(curUser => {
res.render('friends/friendRequests', {
curUser: curUser
});
})
});
results in curUser.recievedRequests = [{ _id : 5ae94b5f29c86c4a343d2d0a }]

How to populate nested entities in mongoose?

I have the following mongoose schema structure
userSchema = new Schema({
roles: [
role: {type: Schema.Types.ObjectId, ref: 'Role' }
]
})
rolesSchema = new Schema({
name: String,
roleEntities: [
{
entity : {type: Schema.Types.ObjectId, ref: 'RoleEntity' },
abilities : [{type: Schema.Types.ObjectId, ref: 'Ability' }]
}
]
}
roleEntitiesSchema = new Schema({
name: String
})
abilitiesSchema = new Schema({
name: String
})
How can i populate all these nested documents while doing a find on the USER model?
I tried using populate as below
User.find(ctx.request.query).populate(
{path: 'roles.role'
,populate: { path: 'roleEntities.entity'}
}).
exec()
but it's not resolving roleEntities.entity
Here's an extreme example of a deep populate nested inside of multiple objects/arrays:
Deal.find()
.populate({
path: 'fund',
populate: [{
path: 'organizer',
populate: {
path: 'banking.accounts.transactions.associatedInvestment',
model: 'Investment'
}
}, {
path: 'documents'
}]
})
You can try chaining populate operations
User.find()
.populate("roles.role")
.populate("roles.role.roleEntities.entity")
Mongoose 4 :
User
.find()
.populate({
path: 'roleIds',
model: 'roles',
populate: {
path: 'otherIds',
model: 'other'
}
})
for me worked the following
.populate({
path: 'favorites.favorite',
model: 'Joke',
populate: {
path: 'user',
model: 'User',
},

Many to many relationships MongoDB mongoose

I have a user schema and users can be friends.
I have a friendship schema:
var friendshipSchema = mongoose.Schema({
from : { type: Schema.Types.ObjectId, ref: 'User' },
to : { type: Schema.Types.ObjectId, ref: 'User' }
});
Now, I want to get all friends from an user foo:
Friendship
.find({
$or : [
{ from : foo._id },
{ to : foo._id }
]
})
The problem is: I want to populate all friends from foo, but not foo himself (since for X friends I would have X foos populated).
How could I achieve that?
Thanks!
This is what I did:
Friendship
.find({
$or : [
{ from : user._id },
{ to : user._id }
]
})
.populate({
path: 'from',
match: { _id: { $ne: user._id }},
select: '-token'
},{
path: 'to',
match: { _id: { $ne: user._id }},
select: '-token'
})
.lean()
.exec(function(err, retData)
{
// Do something here...
});

Resources