Populating and selecting multiple sub-documents mongoose - mongodb

I have a User Model
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
}
email: {
type: String,
required: true,
maxlength: 128,
minlength: 5
},
hashedPassword: {
type: String,
required: false
}
});
module.exports = mongoose.model('users', UserSchema);
And a Post Model
const mongoose = require('mongoose');
const PostSchema = new mongoose.Schema({
description: {
type: String,
required: true
},
comments: [{
comment: {
type: String,
required: true
},
postedBy: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'users'
},
postedOn: {
type: Date,
required: true,
default: Date.now
}
}],
postedBy: {
type: mongoose.Types.ObjectId,
required: true,
ref: 'users'
}
});
module.exports = mongoose.model('answers', AnswerSchema);
I want to fetch post with populated "postedBy"(of POST) also select fields of "name and email" from "postedBy"(of POST). Also, I want to populate "postedBy"(inside comments) and select the same field of "name and email" from "postedBy"(inside comments).
Expecting to see a result like
{
"post": [
{
"_id": "*some mongo id*",
"description": "This is a sample Post for testing",
"postedBy": {
"_id": "5e9285669bdcb146c411cef2",
"name": "Rohit Sharma",
"email": "rohit#gmail.com"
},
"comments": [{
"comment": "Test One Comment",
"postedBy": {
"_id": "5e9285669bdcb146c411cef2",
"name": "Rohit Sharma",
"email": "rohit#gmail.com"
},
}],
"postedOn": "2020-04-19T12:28:31.162Z"
}
]
}

Related

How to return the object in an array object in mongoose

I currently have a UserModel and a House model where the house model contains an array of user objects. However, when I return I want to return an array of user objects instead of just users objectId. How do I accomplish this?
For example, if I run
HouseModel.findbyId("asdf")
it returns:
_id: "asdf"
"name": "name",
"users": [
"620044aa7811fb4ab4619e44",
"620044aa7811fb4ab4619e45"
],
Any help would be appreciated
but I want to return:
``
_id: "asdf"
"name": "name",
"users": [
{_id: "620044aa7811fb4ab4619e44", name: "bob" age: 7,},
{_id: "620044aa7811fb4ab4619e45", name: "bob" age: 7,}
],
``
HouseSchema
const houseSchema = new mongoose.Schema({
name: {
type: String,
required: false
},
users: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
default: [],
required: true,
}
],
UserSchema
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
},
age: {
type: Number,
required: false,
unique: true,
},
use populate
HouseModel.findbyId("asdf").populate('users')

Mongoose - Sub Document Array Issue

I have a "Company" Model which has a number of "Rooms".
I'm able to create the Rooms no problem, and they have a link back to the Company.
The problem is that when I get the Company, the Rooms array has no items.
I can see that the Room exists and has a link back to the Company:
{
"RoomType": 0,
"AllowedRoomRoles": [
"5f999f4f542eed1b8fce5fa9"
],
"Enabled": true,
"_id": "5fb677b453658c7070bf9433",
"RoomName": "Martins Room 2",
"RoomPin": "0001",
"Company": "5fad553db19ca100161a0d8f",
"__v": 0
}
However when I do:
var company = await CompanyModel.findById('5fad553db19ca100161a0d8f');
I get the Company back but the Rooms array has no items in it.
Here are my models:
//Room Schema:
const roomSchema = new Schema({
RoomPin: String,
RoomName: String,
RoomType: { type: RoomType, default: RoomType.MeetingRoom } ,
Company: {type: Schema.Types.ObjectId, ref: 'CompanySchema'},
AllowedRoomRoles: [{type: Schema.Types.ObjectId, ref: 'RoomRoleSchema'}],
Enabled: { type: Boolean, default: true },
}, {
collection: "room"
})
//Company Schema:
const companySchema = new Schema({
CompanyName: { type: String, required: true },
CompanyLogo: { type: String, required: true },
Enabled: { type: Boolean, default: true },
CompanyIdentifier: { type: String, required: true },
CompanyWebsite: { type: String, required: true },
Rooms: [{type: Schema.Types.ObjectId, ref: 'RoomSchema'}],
}, {
collection: "company"
})
Minor update:
Seems doing it this way around is fine?
```var rooms = await RoomModel.find({'Company': company._id.toString() });

find one with multiple conditions mongoose mongodb

I am trying to obtain data from mongodb. This is the scenario. Each user has a following property(array) that takes an array of users id.
The user model is as below
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
followers: [{ type: mongoose.Types.ObjectId, ref: "user" }],
following: [{ type: mongoose.Types.ObjectId, ref: "user" }],
});
in simple terms. I need to use two conditions where postedBy: { $in: req.user.following }, or postedBy:req.user._id
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
body: {
type: String,
required: true,
},
photo: {
type: String,
required: true,
},
likes: [{ type: mongoose.Schema.ObjectId, ref: "user" }],
comments: [
{
text: String,
postedBy: { type: mongoose.Schema.Types.ObjectId, ref: "user" },
},
],
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
},
});
I have not figured out the second condition to add in the code below.
router.get("/getSubPost", requireLogin, async (req, res) => {
try {
const result = await Post.find({
postedBy: { $in: req.user.following },
})
.populate("postedBy", "-password")
.populate("comments.postedBy", "_id name");
res.json({ result });
} catch (error) {
console.log(error);
}
});

mongoose referencing not working when object_id is string

I have two mongo collections, one for department and another one for users
var DeptSchema = new Schema({
name: {
type: String,
required: 'Department Name Missing.'
}},{
timestamps: true
});
DeptSchema.plugin(sequenceGenerator, {
field: '_id',
startAt: '0001',
prefix: 'DEPT'
});
module.exports = mongoose.model('departments', DeptSchema);
//User or staff schema definition
var UserSchema = new Schema({
name: {
type: String,
required: 'User Name Missing.'
},
role: {
type: String,
required: 'Role Missing.',
enum: ['admin', 'sales']
},
passwordHash: String,
passwordSalt: String,
departmentId: {
type: Schema.Types.ObjectId,
required: 'Department Id Missing.',
ref: 'departments'
}
},{
timestamps: true
});
UserSchema.plugin(sequenceGenerator, {
field: '_id',
startAt: '0001',
prefix: 'staff'
});
module.exports = mongoose.model('users', UserSchema);
Now i have inserted one document in departments collection with _id as 'DEPT0001' but while registering a user with data
{ name: 'rahul agarwal',
username: 'rahul43',
password: 'rev#888',
departmentId: 'DEPT0001',
role: 'admin' }
on postman it gives error
{
"errors": {
"departmentId": {
"message": "Cast to ObjectID failed for value \"DEPT0001\" at path \"departmentId\"",
"name": "CastError",
"stringValue": "\"DEPT0001\"",
"kind": "ObjectID",
"value": "DEPT0001",
"path": "departmentId",
"reason": {
"message": "Cast to ObjectId failed for value \"DEPT0001\" at path \"departmentId\"",
"name": "CastError",
"stringValue": "\"DEPT0001\"",
"kind": "ObjectId",
"value": "DEPT0001",
"path": "departmentId"
}
}
},
"_message": "users validation failed",
"message": "users validation failed: departmentId: Cast to ObjectID failed for value \"DEPT0001\" at path \"departmentId\"",
"name": "ValidationError"}
My question should i not use customized _id field for reference, if its feasible, so why I can't reference it.

Mongoose not populating previously saved document with reference to newly saved document

all.
I am writing a MEAN stack application, using Mongoose (4.0.6) with Node/Express to interface with MongoDB, and I am running into difficulty populating saved documents when I later save new documents that the existing document should have a reference to. Specifically, in the app I have a user create an instance of a company before creating their admin account for that company, so when the user registers him/herself as an admin, I'd like the company document to populate its users array with the new user.
Here are my schemas for company and user:
User.js...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.Types.ObjectId;
var userSchema = new Schema({
first_name: { type: String, required: '{PATH} is required!' },
last_name: { type: String, required: '{PATH} is required!' },
username: { type: String, required: '{PATH} is required!', lowercase: true, unique: true },
password: { type: String, required: '{PATH} is required!' },
roles: { type: [String] },
company: { type: ObjectId, ref: 'Company', required: true },
db_permissions: [{ type: ObjectId, ref: 'DataConnection' }],
created_by: { type: ObjectId, ref: 'User' },
created_at: { type: Date, default: Date.now },
updated_at: [{ type: Date, default: Date.now }]
});
var User = mongoose.model('User', userSchema);
module.exports = {
User: User
};
Company.js...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.Types.ObjectId;
var companySchema = new Schema({
name: { type: String, uppercase: true, required: '{PATH} is required!', unique: true },
industry: { type: String, required: '{PATH} is required!' },
phone: { type: String, required: '{PATH} is required!' },
address_line_1: { type: String, uppercase: true, required: '{PATH} is required!' },
address_line_2: { type: String, uppercase: true },
city: { type: String, uppercase: true, required: '{PATH} is required!' },
state_prov: { type: String, uppercase: true, required: '{PATH} is required!' },
postal_code: { type: String, required: '{PATH} is required!' },
country: { type: String, required: '{PATH} is required!' },
logo_url: String,
users: [{ type: ObjectId, ref: 'User' }],
data_connections: [{ type: ObjectId, ref: 'DataConnection' }],
created_at: { type: Date, default: Date.now },
updated_at: [{ type: Date, default: Date.now }]
});
var Company = mongoose.model('Company', companySchema);
module.exports = {
Company: Company
};
Here is the code in my controller:
User.create(userData, function(err, user) {
if(err) {
if(err.toString().indexOf('E11000') > -1) {
err = new Error('Duplicate email');
}
res.status(400);
return res.send({ reason:err.toString() });
}
console.log('company id: ' + user.company);
Company.findById(user.company)
.populate({path: 'users'})
.exec(function (err, company) {
if (err) return handleError(err);
console.log(company.name + '\'s users now includes ' + company.users);
});
res.send(user);
The company (e.g. TEST53) saves to the database correctly with an empty users array:
{
"_id": "55ae421bf469f1b97bb52d5a",
"name": "TEST53",
"industry": "Construction",
"phone": "2352626254",
"city": "GDFGD",
"country": "United States",
"address_line_1": "DSGDFGH",
"state_prov": "GF",
"postal_code": "45645",
"logo_url": "",
"__v": 0,
"updated_at": [
"2015-07-21T12:59:07.609Z"
],
"created_at": "2015-07-21T12:59:07.597Z",
"data_connections": [],
"users": []
}
Then when I create the user, it saves correctly:
{
"_id": "55ae4238f469f1b97bb52d5b",
"username": "test53#test.com",
"password": "$2a$12$ZB6L1NCZEhLfjs99yUUNNOQEknyQmX6nP2BxBvo1uZGlvk9LlKGFu",
"company": "55ae421bf469f1b97bb52d5a",
"first_name": "Test53",
"last_name": "Admin",
"__v": 0,
"updated_at": [
"2015-07-21T12:59:36.925Z"
],
"created_at": "2015-07-21T12:59:36.550Z",
"db_permissions": [],
"roles": [
"admin"
]
}
And I can see that the correct ObjectId prints to the console for user.company:
company id: 55ae421bf469f1b97bb52d5a
But the company's users array doesn't populate with the user's id, and the console.log inside the .exec function prints 'TEST53's users now includes '.
I have tried several ways of wiring this up, with just 'users' instead of { path: 'users' }, writing a function that pushes the user into the array, using .run instead of .exec, but so far without success.
Is there something obvious I'm missing? Thanks in advance for any suggestions!
You're not actually adding the user to the company.
Try this:
Company.findById(user.company, function (err, company) {
if (err) return handleError(err);
// Add the user to the company's list of users.
company.users.push(user);
// Need to save again.
company.save(function(err) {
if (err) return handleError(err);
console.log(company.name + '\'s users now includes ' + company.users);
});
});
res.send(user);
It seems to me that all you want to do is to update the Company model to add the user, as opposed to actually use the (populated) Company document as a response, so I left out an additional Company.findById(...).populate(...) call.