I have the following schemas:
var userSchema = new Schema({
username: String,
rooms: [{type: Schema.Types.ObjectId, ref: 'Room'}]
});
var roomSchema = new Schema({
members: [
{
user:{type:Schema.Types.ObjectId, ref 'User'},
role: String
}
],
messages: [
{
text: String,
meta: {
send: {type: Schema.Types.ObjectId, ref 'User'},
sent_time: Date
}
}
]
});
I wish to obtain all rooms of a particular user and deep populate each room to get populated messages and members arrays so that each sender in a message is populated with username and each member is populated with his/her username, something like this:
User.findById(id).
populate({
path: 'rooms',
populate: [
{
path: 'members.user',
select: 'username'
},
{
path: 'messages.meta.sender',
select: 'username'
}
]
}).exec(function(err, self) { // self becomes deep populated});
Obviously, the above didn't work for me.
Related
I want to populate the fields of a subdocument, which is a discriminated element of a common Schema (Notificationable discriminated into Message or FriendRequest).
This question is quite similar to this one: mongoosejs: populating an array of objectId's from different schemas, which was not solved two years ago. Since mongoose evolved, and discriminator also, I am asking the question again.
What I have tried so far:
Notification.find({_id: 'whatever'})
.populate({
path: 'payload',
match: {type: 'Message'},
populate: ['author', 'messageThread']
})
.populate({
path: 'payload',
match: {type: 'FriendRequest'},
populate: ['to', 'from']
})
.exec();
This does not work, because the path is the same.
So I tried:
Notification.find({_id: 'whatever'})
.populate({
path: 'payload',
populate: [
{
path: 'messageThread',
match: {type: 'Message'},
},
{
path: 'author',
match: {type: 'Message'},
},
{
path: 'from',
match: {type: 'FriendRequest'},
},
{
path: 'to',
match: {type: 'FriendRequest'},
},
]
})
.exec();
Which does not work either, maybe because the match is executed in the subdocument and thus does not have a field type.
Is there any solution for this?
Here are my (main) models, I did not provide User or MessageThread.
The main document:
const NotificationSchema = new Schema({
title: String,
payload: {
type: Schema.Types.ObjectId,
ref: 'Notificationable'
});
mongoose.model('Notification', NotificationSchema);
The payload Parent schema
let NotificationableSchema = new Schema(
{},
{discriminatorKey: 'type', timestamps: true}
);
mongoose.model('Notificationable', NotificationableSchema);
And the two discriminated possibilities:
let Message = new Schema({
author: {
type: Schema.Types.ObjectId,
ref: 'User'
},
messageThread: {
type: Schema.Types.ObjectId,
ref: 'MessageThread'
}
}
Notificationable.discriminator('Message', Message);
And:
let FriendRequest = new Schema({
from: {
type: Schema.Types.ObjectId,
ref: 'User'
},
to: {
type: Schema.Types.ObjectId,
ref: 'User'
}
}
Notificationable.discriminator('FriendRequest', FriendRequest);
I Have following model for a team
var team = new mongoose.Schema({
supervisor: { type: mongoose.Schema.Types.ObjectId, ref: 'employee' }, // SupervisorId
commanders: [{
employee: { type: mongoose.Schema.Types.ObjectId, ref: 'employee' }, //under supervisor
level: { type: Number, defult: 1 }
}]
});
while fetching data from DB I am able to populate supervisor but not employees in commanders array
I tried something like below
db.team.findOne({
supervisor: employeeId
}).populate({
path: 'supervisor',
populate: {
path: 'commanders',
populate: {
path: 'employee',
model
}
}
})
Need help.!!
Try with This:
db.team.findOne({
supervisor: employeeId
}).populate('supervisor commanders.employee')
This is the relevant portion of my Schema:
var classroomSchema = mongoose.Schema({
students: [{
_id: mongoose.Schema.Types.ObjectId,
ref: 'User',
rate: {
type: Number,
default: 200,
},
referrals: [mongoose.Schema.Types.ObjectId],
}],
)};
Here rate and referrals are properties of the students which are valid in the context of that classroom, and cannot be populated from the Students model.
Is there any way to define my schema such that I can keep those fields(rate and referrals) and also use populate to link other fields such as name, age, etc of the student?
Change your schema to this:
var classroomSchema = mongoose.Schema({
students: [{
rate: { type: Number, default: 200 },
user: { ref: 'User', type: Schema.Types.ObjectId },
referrals: [mongoose.Schema.Types.ObjectId],
}],
});
Usage:
classroom
.findOne(...)
.populate('user')
.exec((err, classroom) => {
let student0 = classroom.students[0];
// student0.rate
// student0.user.name
});
I have two collections User and Contact. User will request another user for contact and both userids will be stored in contact collection with status. I want to use the contact and user in many other places, so wrote separate models.
Now I want to get user profile with contact object, the contact object should have the contact user information.
User Schema
var UserSchema = new mongoose.Schema({
name : {
type:String,
default: '',
required:'Please fill name.',
trim: true
},
mobile : {
type:String,
required:'Please fill mobile',
unique:true,
trim:true
},
contacts:[{
type: mongoose.Schema.ObjectId,
ref: 'Contact'
}]
});
Contact Schema
var ContactSchema = new mongoose.Schema({
owner: {
type: mongoose.Schema.ObjectId,
ref: 'User'
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User'
},
status: {
type:String,
default:'pending'
}
});
Profile API
User
.findById(req.body.user_id)
.populate({
path: 'contacts',
select: 'user',
})
.exec(function(err, user){
if (err) return res.send(err);
res.status(200).json({'message':'Profile found.','user':user});
});
Here the response will be as follows:
{
"message": "Profile found.",
"user":
{
"_id": "563037f3fe2b69e40b05c451",
"mobile": "32435345",
"__v": 1,
"contacts":
[
{
"_id": "56303f04f1b8524f0d03d9a7",
"user": "563037bafe2b69e40b05c44e"
}
],
"name": "Lorem"
}
}
In the contacts array, I need the name and mobile field for the connected user along with id. How can I achieve this? Or is there any other better approach in schema design?
You should try mongoose-deep-populate module.
var UserSchema = new Schema({
name: String,
mobile: String,
contacts: [{type: mongoose.Schema.ObjectId, ref: 'Contact'}]
})
var ContactSchema = new Schema({
owner: {
type: mongoose.Schema.ObjectId,
ref: 'User'
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User'
},
status: {
type:String,
default:'pending'
}
});
Initialize the module with a mongoose instance:
var deepPopulate = require('mongoose-deep-populate')(mongoose);
UserSchema.plugin(deepPopulate, options /* more on options below */);
Now you can populate:
User
.findById(req.body.user_id)
.deepPopulate(users, 'contacts.user', function (err, _users) {
// _posts is the same instance as posts and provided for convenience
users.forEach(function (user) {
// post.contacts and user.contacts.user are fully populated
});
});
I have a user schema like this
var userSchema = new mongoose.Schema({
username: String,
following: [{created: {type: Date, default: Date.now}, target: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }}]
});
And a user activity schema:
var activity = new mongoose.Schema({
text: String,
private: Boolean,
_creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }
});
I'm trying to get all the activites where the _creator is $in the following sub-document of the user.
userModel.methods.getNewsfeed = function(callback){
var following_targets = _.pluck(this.following, 'target') // using underscore.js
activityModel.find(
{
$or: [
{
_creator: this._id
}
,
{
$and: [
{ private: { $ne: true } }
, {'_creator': { $in: following_targets }}
]
}
]
}
)
.exec(callback);
}
However this query only returns activites created by the current user. Removing the _creator: this._id part returns an empty array.
I found what was wrong.
I manually inserted sample user documents using the mongo shell, the target in the following array was a String instead of ObjectId, so mongoose could not find it.