Mongoose .populate() does not populate - node.js

I have two schema's Role and User. When I do a Role.find() I want to populate the users with the users that have that specific role.
let roleSchema = new Schema({
name: {
type: String,
required: true,
},
...,
users: [{
type: mongoose.Schema.ObjectId,
ref: 'User'
}]
}, {
timestamps: true,
});
const Role = mongoose.model('Role', roleSchema);
let userSchema = new Schema({
username: {
type: String,
required: true,
},
...,
role: {
type: mongoose.Schema.ObjectId,
ref: 'Role'
},
}, {
timestamps: true,
}
);
const User = mongoose.model('User', userSchema);
When I get the Role with the following code:
Role.findById(req.params.roleId)
.populate('users')
.then(role => {
res.send(role);
}).catch(err => {
res.send(err)
});
It returns the following:
{
"users": [
],
"_id":"5c78006df35ca926534ad865",
"name":"Role",
"createdAt":"2019-02-28T15:38:21.741Z",
"updatedAt":"2019-02-28T15:38:21.741Z",
"__v":0
}
User.find().populate('role') works just fine, but Role.find().populate('users') doesn't.
Am I doing something wrong or don't I need .populate() in this case?

Nevermind. I think I had to use aggregate().lookup() for that all along... since there weren't any ids in Role.users...
Role.aggregate()
.lookup({
from: 'users',
localField: '_id',
foreignField: 'role',
as: 'users'
}).then( role => {
res.send(role);
});
This gave me the response I wanted.

Related

Fetch parent records based on child field record field mongodb

I have User Schema
var UserSchema = mongoose.Schema(
{
email: String,
roles: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Roles',
required: true,
},
],
});
Roles Schema
var RolesSchema = mongoose.Schema({
name: {
type: String,
unique: true,
required: [true, 'A Role must have a name'],
},
});
I want to fetch all users which role name includes Admin in one query.
const t = await User.find({
roles: {
$elemMatch: {
name: 'Admin',
},
},
});
This Always returns empty array
Another I tried
const t = await User.aggregate([
{
$lookup: {
from: 'Roles',
localField: 'roles',
foreignField: '_id',
as: 'roles',
},
},
{
$match: { 'roles.name': 'Admin' },
},
]);
This also returns an empty array. I want all users which have role name = Admin

Mongoose find problem - TypeError: Cannot read property 'find' of undefined

I'm having a issue with a mongoose find() query, which I cannot figure out. the error I receive is "TypeError: Cannot read property 'find' of undefined" which I suspect is an export/import problem. Any help would be greatly appreciated.
here is my scheme model file:
const mongoose = require('mongoose');
const RoleSchema = new mongoose.Schema({
pageGroup: {
type: String,
required: true,
},
level: {
type: String,
required: true,
}
})
const OfficeSchema = new mongoose.Schema({
officeId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Office",
required: true,
},
roleId: {
type: [mongoose.Schema.Types.ObjectId],
required: false,
},
})
const InstanceSchema = new mongoose.Schema({
instanceId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Instance",
required: true,
},
offices: {
type: [OfficeSchema],
required: false,
},
})
const UserSchema = new mongoose.Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
email: {
type: String,
required: false
},
password: {
type: String,
required: false
},
access: {
type: [InstanceSchema],
required: false,
},
permissions: {
type: [RoleSchema],
required: false,
},
activationToken: {
type: String,
required: false,
},
roleId: { // new
type: mongoose.Schema.Types.ObjectId,
// index: true,
ref: 'Role',
// default: null
},
employeeId: {
type: String,
required: false
},
instanceId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Instance',
required: true
},
officeId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Office',
required: true
},
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
})
UserSchema.virtual('instances', {
ref: 'Instance',
localField: 'access.instanceId',
foreignField: '_id',
});
UserSchema.virtual('instances.offices', {
ref: 'Office',
localField: 'access.offices.officeId',
foreignField: '_id',
});
UserSchema.virtual('office', {
ref: 'Office',
localField: 'officeId',
foreignField: '_id',
justOne: true,
});
UserSchema.virtual('name').get(function() {
return this.firstName + " " + this.lastName
});
const User = mongoose.model('User', UserSchema);
module.exports = { User }
here is my function in my controller file:
const { User } = require('./user.model');
async getEmployees(){
const employees = await User.find({
instanceId: this._id,
}, '-password -activationToken -__v -activated')
.populate('office')
.sort([['firstName', 1]])
.exec()
return employees
},
The error points to User being undefined, which can happen when your project has cyclic dependencies (where file A.js depends on file B.js, which in turn depends on file A.js again, either directly or indirectly through another file).
A quick fix is to delay loading the User model until the moment it's actually needed, by moving the require() into getEmployees():
async getEmployees(){
const { User } = require('./user.model');
const employees = await User.find({
instanceId: this._id,
}, '-password -activationToken -__v -activated')
.populate('office')
.sort([['firstName', 1]])
.exec()
return employees
}
But ideally, you should get rid of the cyclic dependency altogether.
I had the same problem on my project. You can fix it by replacing
const { User } = require('./user.model');
of your controller by :
const User = require('./user.model');
Just by removing the brackets made it for me. So I guess you should use destructuring.

How do I find object based on child populated property on mongoose

I'm new in mongoose.
I have a Schema like this:
const sessionSchema = mongoose.Schema({
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
registers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Register',
},
],
date: {
type: Date,
default: Date.now,
immutable: true,
},
});
And register model is this one:
const registerSchema = mongoose.Schema({
sets: [
{
weight: {
type: Number,
},
weightUnit: {
type: String,
default: 'kg',
},
repetitions: {
type: Number,
},
duration: {
type: Number,
},
},
],
session: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Session',
},
exercise: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Exercise',
},
creationDate: {
type: Date,
default: Date.now,
immutable: true,
},
});
I want to find all the sessions created by a user and has an register with an specificied exercise id. I tried this:
const result = Session.find({createdBy: userId, 'registers.exercise': exerciseId}).populate('registers');
But doesn't work. ¿Any suggestion?
Thanks :P
Try this:
Session.aggregate([
{
$match: { createdBy: userId }
},
{
$lookup: {
from: 'Register',
localField: 'registers',
foreignField: '_id',
as: 'registers'
}
},
{
$match: { 'registers.exercise': exerciseId }
}
])
.then((result) => {
console.log('Result: ', result);
})
.catch((err) => {
console.log('Error: ', err);
});
If you are not familiar with MongoDB aggregation framework, the query above might be a bit foreign to you. However, for cross collection queries like you described in your question, the aggregation framework is your best shot(for now).
The $match is basically doing what you would do with a Model.find(), while the $lookup is doing what you would do with a Model.<query>.populate()
You can read more about MongoDB aggregation framework here.

Mongoose populate in array

I try to play with populate but without success ...
It's possible to do this?
I have 2 shema :
- User
import mongoose, { Schema } from 'mongoose'
const userSchema = new Schema({
email: { type: String, unique: true },
password: String,
passwordResetToken: String,
passwordResetExpires: Date,
products: [{
productId: { type: Schema.Types.ObjectId, ref: 'Product' },
dateAdd: { type: Date, default: Date.now }
}]
}, { timestamps: true })
const User = mongoose.model('User', userSchema)
export default User
And Product :
import mongoose, { Schema } from 'mongoose'
const productSchema = new Schema({
domain: String,
originUrl: { type: String },
price: Number,
img: String,
userFollow: [{ type: Schema.Types.ObjectId, ref: 'User' }]
})
const Product = mongoose.model('Product', productSchema)
export default Product
So I want to retrieve all the info for each of my prodcutId
I try this way (and many others without success):
User.findOne({ _id: userId }).populate({
path: 'products.productId',
populate: { path: 'products.productId', model: 'Products' }
}).exec(function (err, products) {
if (err) {
console.log('errors :' + err)
}
console.log('Product => ' + util.inspect(products))
})
Populate has no effect, same result with just the findOne()
I think User.findOne({ _id: userId }).populate('products.productId') should work.
Try using aggregate function of MongoDB and $lookup.
Users.aggregate([
{
"$match":
{
_id: user.id
}
},
{
"$lookup":
{
from: "Product",
localField: "products",
foreignField: "_id",
as: "products"
}
}
])
.exec()
.then((result) => {
//your result
})
.catch((err) => {
// if any error
});

Displaying friends list using node.js and MongoDB

I am new to a node.js and I am trying to use this application https://github.com/knoldus/Node.js_UserLogin_Template
However, I cannot see friends list. I do not know what is the problem with ?
Could you help me with issue ?
Thanks
//Your user schema is looks like that
const userSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
//unique: true,
required: true
},
password: {
type: String,
required: true
},
friends: {
type: Array // here you can put your friends collections _id like this [ObjectId("id1"), ObjectId("id2")]
}
});
const FriendSchema = new Schema({
user_from: {
type: Schema.Types.ObjectId,
ref: "users",
required: true
},
user_to: {
type: Schema.Types.ObjectId,
ref: "users",
required: true
},
is_accepted: {
type: Boolean,
default: false
},
date: {
type: Date,
default: Date.now
}
});
//and your query will look like that --
FriendModel.aggregate([
{
$lookup: {
from: "users", // users collection
localField: "_id", // friends collection id
foreignField: "friends", // friends field in you users collection document
as: "myfriends" //any alias name you can use
}
},
{
$match: { // matching condition for current user's friends from friends collection including current user
$or: [
{ user_to: mongoose.Types.ObjectId(req.user.id) }, // req.user.id referrers to logged in user object id
{ user_from: mongoose.Types.ObjectId(req.user.id) },
]
},
$match: { is_accepted: true} // that condition is for is user accepted friend request or not.
}
,
{ // filtering logged in user from the friend list
$project: {
myfriends: { // myfriends is alias name that you used in $loopup part
$filter: {
input: "$myfriends",
as: "item",
cond: { $ne: [ "$$item._id", mongoose.Types.ObjectId(req.user.id) ] }
}
}
}
}
])

Resources