Mongoose: Populate referenced SubDocument - node.js

I've the following schemas:
Occurence that references a competence in the CostCenter subdocuments competences.
const OccurrenceSchema = new mongoose.Schema({
date: {
type: Date,
default: Date.now,
},
competence: {
type: mongoose.Schema.Types.ObjectId,
ref: 'CostCenter.competences',
},
...
})
CostCenter where I've an array of subdocuments that can be ref by Occurence.
const CostCenterSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
},
competences: [CompetenceSchema],
});
And finally the Competence.
const CompetenceSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
},
});
When I try to populate the competence, I get "Schema hasn't been registered for model \"CostCenter.competences\".\nUse mongoose.model(name, schema)".
const occurrence_list = (request, response) => {
Occurrence.find()
.populate('occurrence origin tag entity method priority competence')
.then(occurrences => response.send(occurrences))
.catch(e => response.send(e));
};
How can I possibly populate the occurrence when referencing a subdocument?

First, you need to change your Occurrence model to this
const OccurrenceSchema = new mongoose.Schema({
date: { type: Date, default: Date.now },
competence: { type: mongoose.Schema.Types.ObjectId, ref:'CostCenter' }
});
mongoose.model('Occurrence', OccurrenceSchema);
and CostCenter model:
const CostCenterSchema = new mongoose.Schema({
name: { type: String, required: true, trim: true },
competences:[{ type: mongoose.Schema.Types.ObjectId, ref: 'Competence' }],
});
mongoose.model('CostCenter', CostCenterSchema);
finally Competence model:
const CompetenceSchema = new mongoose.Schema({
name: { type: String, required: true, trim: true }
});
mongoose.model('Competence', CompetenceSchema);
To populate the competence from Occurrence, you can do so:
Occurrence.find({ your_query })
.populate('competence')
.then(occurrences => response.send(occurrences))
.catch(e => response.send(e));
Hope it helps!

Related

Referencing a specific attribute to another Schema in mongoose

May I know how to reference a specific field like in my code is the flowerName? I want to reference flowerName to the inventorySchema from stockSchema. Will this work?
const inventorySchema = ({
id: {type: mongoose.Schema.Types.ObjectId, ref: 'Stocks', required: true},
flowerName: {ref: 'Stocks', required: true},
orderName: {
type: String,
required: true
}
})
module.exports = mongoose.model('Inventory', inventorySchema);
const stockSchema = new Schema({
id: {
type: Number
},
flowerName: {
type: String,
required: true
}
module.exports = mongoose.model('Stocks', stockSchema);
You should reference inventory from stock
const inventorySchema = new Schema({
orderName: {
type: String,
required: true,
},
flowerName: {
type: String,
required: true,
},
});
module.exports = mongoose.model('Inventory', inventorySchema);
const stockSchema = new Schema({
id: {
type: Number
},
inventory: {
type: Schema.Types.ObjectId,
ref: 'Inventory',
required: true
}
});
module.exports = mongoose.model('Stocks', stockSchema);
You should then be able to reference flowerName by populating stock instances with:
const stock = Stocks.findOne({}).populate('inventory').exec();
if (stock) stock.inventory.flowerName

How to receive information from a model inside an array in another model? (mongoose)

I have a "cart" model, and within my "order" model, I would like to have an array that receives the information sent by "cart" stored in an array. How can I do this through ref?
const mongoose = require('mongoose');
const CartSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
note: {
type: String,
required: true,
},
price: {
type: Number,
required: false,
},
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Cart", CartSchema);
order
const mongoose = require('mongoose');
const OrderSchema = new mongoose.Schema(
{
list: {
name: String,
notes: String,
},
totalAmount: {
type: Number,
required: true,
},
payment: {
type: String,
required: true,
},
address: {
type: String,
required: true,
},
addressNote: {
type: String,
required: false,
},
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Order", OrderSchema);
Here in "list" I would like it to be an array that receives cart model information
Can I do this through ref? What would be the best possible way?

How to receive an array from a model inside another model? (mongoose) (mongoDB)

I have an order model/schema, and my goal is that in this model in "list", I receive the information from the model cart in array format. How could I do this using ref?
cart model
const mongoose = require('mongoose');
const CartSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
note: {
type: String,
required: true,
},
price: {
type: Number,
required: false,
},
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Cart", CartSchema);
order
const mongoose = require('mongoose');
const OrderSchema = new mongoose.Schema(
{
list: {
name: String,
notes: String,
},
totalAmount: {
type: Number,
required: true,
},
payment: {
type: String,
required: true,
},
address: {
type: String,
required: true,
},
addressNote: {
type: String,
required: false,
},
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Order", OrderSchema);
Basically receive in array format the information of the model cart in "list" in model order
You should define your list as an array of ObjectIds referring to the Cart model:
const OrderSchema = new mongoose.Schema(
{
list: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Cart'
}],
...
});
Then, to retrieve the values in list, just populate the Order:
Order.find({}).populate('list').exec();

How to 'join' or populate an array

Here is my very basic product schema:
const productSchema = new Schema({
productName: {
type: String,
required: true,
},
productDescription: {
type: String,
},
productPrice: {
type: Number,
},
});
module.exports = mongoose.model("Product", productSchema);
These products are listed out and a user can add a quantity for each. I am storing in an array of objects as per below. I want to join these two collections together so that I can output the qty of products selected by the user. I believe I need to use populate here but not sure how to set up the Refs and so on.
const PartySchema = new Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
catering: [{ id: mongoose.Types.ObjectId, qty: Number }],
created_at: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Party", PartySchema);
I'm sharing this solution with the assumption that the catering field is the sub-document array pointing to the Product Schema:
The Product Schema is fine so it stays the same (although to keep to convention I would advice naming your schema 'Products' instead of 'Product', Mongo Naming Covention):
const productSchema = new Schema({
productName: {
type: String,
required: true,
},
productDescription: {
type: String,
},
productPrice: {
type: Number,
},
});
module.exports = mongoose.model("Products", productSchema);
And next the Party Schema would be:
const PartySchema = new Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
catering: [{
id: {
type: mongoose.Types.ObjectId,
ref: 'Products',
},
qty: {
type: Number,
}
}],
created_at: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Parties", PartySchema);

Mongoose(mongoDB) Linking multiple schema's

Im relatively new to MongoDB and Mongoose. Im much used to MySQL so in used to inner joining tables on calls. Ive read a lot that you can link two Mongoose Schemas to achieve the same outcome. How would like like the two schemas together to when I make a call to get a chore by id it'll return the chore and then for the assignedTo & createdBy have the user scheme data for the said userId?
Chore Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ChoreSchema = new Schema({
title: {
type: String,
required: true
},
desc: {
type: String,
required: true
},
time: {
type: Number,
required: true
},
reaccurance: {
type: [{
type: String,
enum: ['Daily', 'Weekly', 'Bi-Weekly', 'Monthly']
}]
},
reward: {
type: Number,
required: true
},
retryDeduction: {
type: Number,
required: false
},
createdDate: {
type: Date,
default: Date.now
},
createdBy: {
type: String,
required: true
},
dueDate: {
type: Date,
required: true
},
status: {
type: [{
type: String,
enum: ['new', 'pending', 'rejected', 'completed', 'pastDue']
}],
default: ['new']
},
retryCount: {
type: Number,
default: 0,
required: false
},
rejectedReason: {
type: String,
required: false
},
familyId: {
type: String,
required: true
},
assignedTo: {
type: String,
required: false,
default: ""
}
});
let Chores = module.exports = mongoose.model('Chores', ChoreSchema);
module.exports.get = function (callback, limit) {
Chores.find(callback).limit(limit);
};
User Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
role: {
type: [{
type: String,
enum: ['Adult', 'Child']
}]
},
birthday: {
type: String,
required: false
},
familyId: {
type: String,
required: true
},
balance: {
type: Number,
required: true,
default: 0.00
}
});
let Users = module.exports = mongoose.model('Users', UserSchema);
module.exports.get = function (callback, limit) {
Users.find(callback).limit(limit);
};
Im trying to link ChoreSchema.createdBy & ChoreScheme.assignedTo by UserSchema._id
How I make the call in Node.js:
exports.index = function(req, res) {
Chore.get(function(err, chore) {
if (err)
res.send(err);
res.json({
message: 'Chore List',
data: chore
});
});
};
Mongoose has a more powerful alternative called populate(),
which lets you reference documents in other collections.
https://mongoosejs.com/docs/populate.html
Here is how you can link ChoreSchema.createdBy and ChoreScheme.assignedTo by UserSchema._id
var mongoose = require('mongoose');
const { Schema, Types } = mongoose;
var UserSchema = new Schema({
firstName: { type: String, required: true },
...
})
var ChoreSchema = new Schema({
title: { type: String, required: true },
...
//The ref option is what tells Mongoose which model to use during population
assignedTo: { type: Types.ObjectId, ref: 'Users' },
createdBy: { type: Types.ObjectId, ref: 'Users' },
})
let Chores = mongoose.model('Chores', ChoreSchema);
let Users = mongoose.model('Users', UserSchema);
Then in your express route handler you can populate assignedTo & createdBy like this
router.get('/chores/:id', function (req, res) {
const choreId = req.params.id;
Chores.find({ _id: choreId })
.populate('createdBy') // populate createdBy
.populate('assignedTo') // populate assignedTo
.exec(function (err, chore) {
if(err) {
return res.send(err)
}
res.json({ message: 'Chore List', data: chore });
});
})

Resources