Mongoose populate method - node.js

I am having the most awful trouble trying to get the populate feature in mongoose to work. I have looked at all the threads here on SO and nothing has helped. My schema is mapped out below.
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Prodcut Feature Extra
*/
var extra = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Product name',
trim: true
},
price: {
type: Number,
default: 0
},
description: {
type: String,
trim: true
},
toolTip: {
type: String,
trim: true,
min: 3,
max: 140
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
/**
* Product Feature Schema
*/
var feature = new Schema({
name: {
type: String,
default: '',
required: 'Please fill feature name',
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
/**
* Product Schema
*/
var ProductSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Product name',
trim: true
},
created: {
type: Date,
default: Date.now
},
features: [feature],
extras: [extra],
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Feature', feature);
mongoose.model('Extra', extra);
mongoose.model('Product', ProductSchema);
I have tried all of the following queries in a Mongoose Repl but nothing works
models.Product.find().populate("Extra", "name").exec()
models.Product.find().populate({path: "extras", location: "Extra"}).exec()
models.Product.find().populate('extras', 'name').exec()
models.Product.find().populate('extras', 'Extra').exec()
Does anyone have any suggestions? This is killing me!!

Just curious!
This initialization below, isn't has to be done before referencing in ProductSchema?
mongoose.model('Feature', feature);
mongoose.model('Extra', extra);
Something like this
mongoose.model('Feature', feature);
mongoose.model('Extra', extra);
var ProductSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Product name',
trim: true
},
created: {
type: Date,
default: Date.now
},
features: [ {
type: Schema.ObjectId,
ref: 'Feature'
}],
extras: [ {
type: Schema.ObjectId,
ref: 'Extra'
}],
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
Than this should work
models.Product.find().populate("extras")

Related

How to update a specific object in a array of objects by Item ID in Node.js and Mongoose

I need a code in Express.Js and Mongodb where I can change an exact string inside an object through the id of the item, I need to change the string "colorSelected" to a new value, changing only what I put in the body, in my previous failed attempts every change I made would change the entire object, I don't want that, thank you in advance.
Router Cart.js
//update color cart
router.patch("/cart/:id", Auth, async (req, res) => {
});
Model Cart.js
const mongoose = require('mongoose')
const ObjectID = mongoose.Schema.Types.ObjectId
const cartSchema = new mongoose.Schema({
owner : {
type: ObjectID,
required: true,
ref: 'User'
},
items: [{
itemId: {
type: ObjectID,
ref: 'Item',
required: true
},
img: String,
name: String,
colorSelected: String,
colors: Array,
stock: Number,
quantity: {
type: Number,
required: true,
min: 1,
default: 1
},
price: Number
}],
bill: {
type: Number,
required: true,
default: 0
}
}, {
timestamps: true
})
const Cart = mongoose.model('Cart', cartSchema)
module.exports = Cart
Model Item.js
const mongoose = require('mongoose')
const ObjectID = mongoose.Schema.Types.ObjectId
const reviewSchema = mongoose.Schema(
{
name: { type: String, required: true },
rating: { type: Number, required: true },
comment: { type: String, required: true },
user: {
type: ObjectID,
required: true,
ref: 'User'
},
},
{
timestamps: true,
}
)
const itemSchema = new mongoose.Schema({
images: [{
name: {
type: String,
required: true
},
src: {
type: String,
required: true
},
color: {
type: String,
required: true
},
}],
owner : {
type: ObjectID,
required: true,
ref: 'User'
},
name: {
type: String,
required: true,
trim: true
},
description: {
type: String,
required: true
},
category: {
type: Number,
required: true
},
price: {
type: Number,
required: true
},
stock: {
type: Number,
required: true
},
visibility: {
type: Boolean,
required: true
},
reviews: [reviewSchema],
rating: {
type: Number,
required: true,
default: 0,
},
numReviews: {
type: Number,
required: true,
default: 0,
}
}, {
timestamps: true
})
const Item = mongoose.model('Item', itemSchema)
module.exports = Item

Deep population not working with embedded document

I have three documents as below:
var TrackAudioSchema = new Schema({
track_id: {
type: Number,
},
track_path:{
type:String,
required:'Please upload audio track'
}
});
mongoose.model('TrackAudio', TrackAudioSchema);
var trackSchema = new Schema({
title: {
type: String,
trim:true,
required:'Please fill track title'
},
version : {
type: String,
trim: true,
default: ''
},
trackpath:{
type: Schema.ObjectId,
ref: 'TrackAudio'
},
});
var AlbumSchema = new Schema({
language: {
type: String,
default: '',
trim: true
},
tracks:[trackSchema],
user: {
type: Schema.ObjectId,
ref: 'User'
},
)};
AlbumSchema.plugin(deepPopulate);
mongoose.model('Album', AlbumSchema);
but when I try to populate trackpath from trackSchema using the below query, it doesn't populate:
Album.findById(albumId)
.populate('user','name label').
deepPopulate('tracks.trackpath').
exec(function(err, albumdetail) {
}
Please help.
You're missing:
mongoose.model('Track', TrackSchema);

Mongoose Complex Query by Subdocument

I need to find a Project by either Owner, Manager, or one of the Team Members. Here's how the schema looks like:
var project = new mongoose.Schema({
title: { type: String, require: true },
slug: { type: String, require: true },
description: { type: String, require: true },
descriptionHtml: { type: String, require: true },
nextVanityId: { type: Number, default: 1 },
owner: { type: ObjectId, ref: 'Member', require: true },
teams: [{ type: ObjectId, ref: 'Team' }],
managers: [{ type: ObjectId, ref: 'Member' }]
};
var team = new mongoose.Schema({
name: { type: String, require: true },
slug: { type: String, require: true },
project: { type: ObjectId, require: true, ref: 'Project' },
created: { type: Date, require: true, default: Date.now },
members: [{ type: ObjectId, default: null, ref: 'Member' }]
};
My query method looks like this:
function findByMember (member, done) {
var id = member._id;
Project
.find()
.or([
{ owner: id },
{ managers: id },
{ 'teams.members': id }
])
.exec(done);
}
Currently it works for both owners and managers, but I'm drawing blanks when querying the members collection of each team. What should I use?
In order for your query to work you can approach the problem in 2 ways.
Solution 1
Have your teams as an embedded document in projects:
var team = new mongoose.Schema({
name: { type: String, require: true },
slug: { type: String, require: true },
project: { type: ObjectId, require: true, ref: 'Project' },
created: { type: Date, require: true, default: Date.now },
members: [{ type: ObjectId, default: null, ref: 'Member' }]
};
var project = new mongoose.Schema({
title: { type: String, require: true },
slug: { type: String, require: true },
description: { type: String, require: true },
descriptionHtml: { type: String, require: true },
nextVanityId: { type: Number, default: 1 },
owner: { type: ObjectId, ref: 'Member', require: true },
teams: [team],
managers: [{ type: ObjectId, ref: 'Member' }]
};
This way your project document will have the team information and the teams.members makes sense.
Solution 2
Denormalise your Team data to have only the relevant information embedded:
var team = new mongoose.Schema({
name: { type: String, require: true },
slug: { type: String, require: true },
project: { type: ObjectId, require: true, ref: 'Project' },
created: { type: Date, require: true, default: Date.now },
members: [{ type: ObjectId, default: null, ref: 'Member' }]
};
var project = new mongoose.Schema({
title: { type: String, require: true },
slug: { type: String, require: true },
description: { type: String, require: true },
descriptionHtml: { type: String, require: true },
nextVanityId: { type: Number, default: 1 },
owner: { type: ObjectId, ref: 'Member', require: true },
teams: [{
_id: { type: ObjectId, ref: 'Team' },
members: [{ type: ObjectId, default: null, ref: 'Member' }]
}],
managers: [{ type: ObjectId, ref: 'Member' }]
};
In this second approach you need to keep the Team document and the denormalised data in sync.

Is it possible to have an array of alternative subdocument schemas in mongoose

Is it possible to have an array of alternative subdocument schemas in mongoose?
For instance, take this made up scenario: if i have a main schema for a person and i have a field called vehicles of type array, i want to be able to define sub document schemas, but for each vehicle type (car, motorbike, bike, bus etc etc ) :
var car = new mongoose.Schema({
make: { type: String, required: true, default: 'Ford', trim: true },
model: { type: String, trim: true },
wheels: Number,
});
var motorbike = new mongoose.Schema({
make: { type: String, required: true, default: 'Honda', trim: true },
model: { type: String, trim: true },
seats: Number,
});
var bike = new mongoose.Schema({
make: { type: String, required: true, default: 'MuddyFox', trim: true },
model: { type: String, trim: true },
lights: Number,
});
var bus = new mongoose.Schema({
make: { type: String, required: true, default: 'MAN', trim: true },
model: { type: String, trim: true },
dents: Number,
});
/* person */
var person = new mongoose.Schema({
name: { type: String, required: true, default: 'Joe Bloggs', trim: true },
timeCreated: { type: Date, required: true, default: Date.now },
vehicles: [car, motorbike, bike, bus] /* this is what i want to do */
});
db.model('person', person);
Note the person schema.
So that person can have any of those vehicles, but the data for each vehicle is still validated against it's own schema.
Thanks in advance
There is a mongoose plugin called mongoose-schema-extend, that will allow you to enable Schema Inheritance for Mongoose, and basically I think, you are looking for this functionality.
Please check the github project:
https://github.com/briankircho/mongoose-schema-extend
You can create a Vehicle schema, add it as an array to the Person schema, and extend the Vehicle for your different type of vehicles.
I couldn't find any examples of multiple embedded documents being passed as an array.
Perhaps you could rejig things like this:
var car = new mongoose.Schema({
make: { type: String, required: true, default: 'Ford', trim: true },
model: { type: String, trim: true },
wheels: Number,
});
var motorbike = new mongoose.Schema({
make: { type: String, required: true, default: 'Honda', trim: true },
model: { type: String, trim: true },
seats: Number,
});
var bike = new mongoose.Schema({
make: { type: String, required: true, default: 'MuddyFox', trim: true },
model: { type: String, trim: true },
lights: Number,
});
var bus = new mongoose.Schema({
make: { type: String, required: true, default: 'MAN', trim: true },
model: { type: String, trim: true },
dents: Number,
});
var transport = new mongoose.Schema({
car: [car],
motorbike: [motorbike],
bike: [bike],
bus: [bus]
});
/* person */
var person = new mongoose.Schema({
name: { type: String, required: true, default: 'Joe Bloggs', trim: true },
timeCreated: { type: Date, required: true, default: Date.now },
vehicles: [transport]
});
db.model('person', person);
If that doesn't work, then as described in this SO question you can use mongoose populate. This method is now more effective following the addition of deep population was added in Mongoose Deep 3.6.
So you could do soemthing like:
var personSchema = Schema({
_id : 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' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
There's also a mongoose plugin to aid with this functionality called mongoose-deep-populate which is very up-to-date.

one to many relationship in mongoose

I'm using mean stack to create a hybrid app.I'm using nosql to create DB in mongoose.My DB consists of two tables one is 'donors' and another one is 'bloodGroup'.
My 'bloodGroup' schema is as follows:
module.exports = function(mongoose) {
var Schema = mongoose.Schema;
/* bloodGroup Schema */
var bloodGroupSchema = new Schema({
name: { type: String, required: true }
});
}
My 'Donor'schema is as follows:
/* Donor Schema */
var DonorSchema = new Schema({
Name: { type: String, required: true },
DOB: { type: Date, required: true, trim: true },
Sex: { type: String },
BloodGroupID: { type: Schema.Types.ObjectId, ref: 'BloodGroup', required: true },
ContactNo: { type: String, required: true },
LocationId: { type: Schema.Types.ObjectId, ref: 'Location', required:true },
EmailId: { type: String, required: true },
Password: { type: String, required: true }
});
When many donors refer to a single blood group then BloodGroup object Id error is reported.How to solve this problem?
You can refer this link for documentation: http://mongoosejs.com/docs/populate.html
Saving Refs
/* Donor Schema */
var DonorSchema = new Schema({
_id : {type: Number},
Name: { type: String, required: true },
DOB: { type: Date, required: true, trim: true },
Sex: { type: String },
BloodGroupID: { type: Schema.Types.ObjectId, ref: 'BloodGroup', required: true },
ContactNo: { type: String, required: true },
LocationId: { type: Schema.Types.ObjectId, ref: 'Location', required:true },
EmailId: { type: String, required: true },
Password: { type: String, required: true }
});
/* bloodGroup Schema */
var bloodGroupSchema = new Schema({
_bid :{ type: Number, ref: 'Donor' },
name: { type: String, required: true }
});
module.exports = mongoose.model('Donor', DonorSchema);
module.exports = mongoose.model('Blood', bloodGroupSchema);
var vidya = new Donor({ _id: 0, name: 'Vidya', sex: 'F' });
vidya.save(function (err) {
if (err) return handleError(err);
var blood = new BloodGroup({
name: 'B+',
_bid: vidya._id // assign the _id from the Donor
});
blood.save(function (err) {
if (err) return handleError(err);
// thats it!
});
});
Mongo is not a Relational database, relation one to many does not exist in mongDB. The question is quite confusing, but following the title, you should either embed the donnors into the BloodGroup, or create an Id field unique to which you will refer and do two queries.

Resources