I m trying to populate a mongoose model where I only want the returned items to be the ones that are matched with an ID.
Edit update: In the User model below, I need to first find the correct user by id, then for the task property, I need to populate it where the projectID matches req.params.ID. How can I only populate the tasks where the projectID matches the req.params.ID. I have included my full User model as well as the Task model
//User Schema
var UserSchema = new Schema({
name: {
type: String,
trim: true,
required: "First Name is Required"
},
username: {
type: String,
trim: true,
required: "Username is Required"
},
skills: {
type: String,
trim : true
},
avatar: {
type: String
},
SQLid: {
type: Number
},
userCreated: {
type: Date,
default: Date.now
},
lastUpdated: {
type: Date
},
adminTeams: [{
type: Schema.Types.ObjectId,
ref: "Team"
}],
team: [{
type: Schema.Types.ObjectId,
ref: "Team"
}],
task: [{
projectID: {
type: String
},
theTask: {
type: Schema.Types.ObjectId,
ref: "Task"
}
}]
});
//Task Schema
var TodoSchema = new Schema({
task: {
type: String
}
});
How can I only get the task populated where the projectID is equal to a specific ID. I tried
User.findById({ "_id": req.params.id }).populate({ path: 'task', match: {projectID: req.params.pID}, select: 'theTask' })
.exec(function(err, docs){
console.log("POPULATE TASKS DOCS", docs)
But this is showing that the docs is empty.
you can use $elemMatch ,it will give you all those docs which matches your projectId and populate your task document .
So the query would be -
var query={
task:{
$elemMatch:{
projectId: req.params.id
}
}
}
User.find(query)
.populate('theTask')
.select('theTask') // use for getting selective data from document
.exec(function(){}) //your callback fuction
Hope I answer your question.
Thanks.
In your task schma you have kept the type of the task type as string and in your user schema the theTask have the refrence of the task and task its Self is just a string . Thats why it is not being populated ..
So change the task schema to (Keep it simple)-
var Task= new Schema({
name :string
});
Populate need refrence Id to get the whole document
Related
I have two mongodb model as following.
const CompanySchema = new Schema(
{
sections: [{
name: { type: String },
budgets: [{ // indicates from CalcSchema
index: { type: Number },
title: { type: String },
values: [Number],
sum: { type: Number, default: 0 },
}],
}]
},
{ timestamps: true }
);
const CalcSchema = new Schema({
budget: {
type: Schema.Types.ObjectId, // I want to populate this field. this indicates budget document in Company model
ref: "Company.sections.budgets" //it's possible in mongoose?
},
expense: {
type: Number,
default: 0
}
});
budget field indicate one of budgets field in CompanySchema.
So I want to populate when get Calc data.
But I don't how to populate embedded document.
I tried set ref value to ref: "Company.sections.budgets". but it's not working.
Please anyone help.
Finally, I found answer myself.
There is useful plugin for it.
https://github.com/QuantumGlitch/mongoose-sub-references-populate#readme
And I learned that my schema structure was wrong. It's anti-pattern in mongodb.
I have my mongoose schema as follow
const instructorSchema = new mongoose.schema({
coursesByMe: [
{
course: {
type: ObjectId,
ref: "Course",
},
submissions: {
type: Map,
of: Submission.schema,
},
},
],
active: {
type: Boolean,
default: false,
},
});
My submission schema is a simple schema
const submissionSchema = new mongoose.Schema({
user: {
type: ObjectId,
ref: "User",
},
subFile: String,
});
module.exports = mongoose.model("Submission", submissionSchema);
I want to populate the user field but I am unable to as the type of submissions is of map type schema.
Any help with this would be really grateful. Thank you.
Task model
const TaskSchema = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref: 'User'
},
title: {
type: Schema.Types.String,
required: true
},
description: Schema.Types.String,
createdDate: {
type: Schema.Types.Date,
default: Date.now()
},
position: {
type: Schema.Types.Number,
default: 0
},
categoryId: [{
type: Schema.Types.ObjectId,
ref: 'Category'
}]
});
Category model
const CategorySchema = new Schema({
title: {
type: Schema.Types.String,
required: true
},
description: {
type: Schema.Types.String,
},
categoryThumbnail: {
type: Schema.Types.String,
default: ''
},
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
createdDate: {
type: Schema.Types.Date,
default: Date.now()
}
});
When creating a task, the user can assign a category. Do I need to check the category owner before adding the task to Mongodb. If so, what is the best way to do this? Options:
1. Make a request to the database for all categories and check the user id.
2. Store the category id in the user document and, upon receipt of the request, check this list.
So if the User can create multiple categories and each category is only accessible by the User who created it you have a one-to-many association. In this situation it seems your Option 1 is what you want. Keep the user id on the category and then query all categories that have the user id you're looking for.
Edit:
If possible, I would recommend that you limit the categories the user sees when creating a task to only be categories created by that user. If that is not possible, then you could do one query to grab all the categories from the list of category IDs sent to the server and loop through the results checking if the user IDs are the same.
Category.find({
'id': { $in: [
mongoose.Types.ObjectId('4ed3ede8844f0f351100000c'),
mongoose.Types.ObjectId('4ed3f117a844e0471100000d'),
mongoose.Types.ObjectId('4ed3f18132f50c491100000e')
]}
}, function(err, docs){
docs.forEach(item => {
return item.userId === userId; //compare to userId that sent the request
}
});
Is there a way in mongoose + Node.js/Express to define the relation between the foreign key field and what I refer to that field in the model is? My issue is that I have a mongo database where my foreign keys are all formatted like 'exampleId' instead of 'example'. I could just call out 'exampleId' directly but then it leads to weird things like when I populate 'exampleId' instead of 'example' (which is confusing because once populated, it is now the 'example' itself instead of its id).
Here is how I do it now and it works with my graphQL server, but only if my field in the database is 'course' while my database's field is 'courseId'
const CourseSchema = new Schema({
_id: { type: String },
sections: [{
type: Schema.Types.String,
ref: 'Section'
}],
});
const SectionType = new GraphQLObjectType({
name: 'SectionType',
fields: () => ({
id: { type: GraphQLID },
courseId: {
type: require('./course_type'),
resolve(parentValue) {
return Section.findById(parentValue)
.populate('course')
.then(section => section.course);
}
},
}),
});
I figured it out! With the newest version of mongoose, you actually can use virtual fields to accomplish what I wanted to do and this technique allows for flexibility in laying out your schema. Say that my MongoDB collections look like the following:
Courses { _id, sectionIds }
Lectures { _id, courseId }
I can use the following schema in mongoose and it will allow me to refer to course.lectures or lecture.course instead of the usual course.lectureIds or section.courseId:
const CourseSchema = new Schema({
_id: { type: String },
});
CourseSchema.virtual('sections', {
type: Schema.Types.String,
ref: 'Section',
localField: 'sectionIds',
foreignField: '_id',
justOne: false,
});
CourseSchema.statics.findSections = function(id) {
return this.findById(id)
.populate('sections')
.then(course => course.sections);
}
const SectionSchema = new Schema({
_id: { type: String },
});
SectionSchema.virtual('course', {
type: Schema.Types.String,
ref: 'Course',
localField: 'courseId',
foreignField: '_id',
justOne: true,
});
Actually MongoDB isn't a relational database. You can alter the field and its name whatever you like. Ex I Have an Owner(Meteor.users) table and Patient Table with this column
ownerid : {type: String, min: 1},
firstname: {type: String, min: 1},
lastname: {type: String, min: 1},
middlename: {type: String, min: 1, optional: true},
createdbyid: { type: String },
createdbyname: { type: String },
createdat: { type: Date, defaultValue: new Date() },
updatedbyid: { type: String, optional: true },
updatedbyname : { type: String, optional: true },
updatedat: { type: Date, defaultValue: new Date() },
I can easily stamp the value of my {Meteor.Users()._id} to ownerid of my designated patient by just processing them at meteor.methods. You don't have to worry about foreign keys mongo doesn't do relational databases you can customize your database whatever you like. I Hope this helps ;)
Mongoose Documentation posits that _id has to be used in refs and that[i]t is important to match the type of _id to the type of ref. , e.g.:
var personSchema = Schema({
_id : Number, //it is `Number`
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }] // use `Number` to match
});
I also wonder if by 'database' you mean 'collection'.
can someone please help me with population of this schema? I need to populate array of Staff by their userId.
var PlaceSchema = new Schema ({
name: { type: String, required: true, trim: true },
permalink: { type: String },
country: { type: String, required: true },
...long story :D...
staff: [staffSchema],
admins: [adminSchema],
masterPlace:{ type: Boolean },
images: []
});
var staffSchema = new Schema ({
userId: { type: Schema.Types.ObjectId, ref: 'Account' },
role: { type: Number }
});
var adminSchema = new Schema ({
userId: { type: Schema.Types.ObjectId, ref: 'Account'}
})
var Places = mongoose.model('Places', PlaceSchema);
I tried to use this query, but without success.
Places.findOne({'_id' : placeId}).populate('staff.userId').exec(function(err, doc){
console.log(doc);
});
Polpulation is intended as a method for "pulling in" information from the related models in the collection. So rather than specifying a related field "directly", instead reference the related fields so the document appears to have all of those sub-documents embedded in the response:
Places.findOne({'_id' : placeId}).populate('staff','_id')
.exec(function(err, doc){
console.log(doc);
});
The second argument just returns the field that you want. So it "filters" the response.
There is more information on populate in the documentation.