How to use mongoose getter - mongoose

I have three fields in my mongoose schema and i want to retrieve only one which will be the average of the other two.
I tried to use mongoose get but I dont know if I am using it correctly.
Here is my schema
const schema = new Schema({
totalCarrots: {type: Number},
numberOfRabbits: {type: Number},
average: {
type: Number,
get: function () {
const average = this.totalCarrots / this.numberOfRabbits;
if (average) return Math.ceil(average);
return null;
}
}
});
I expected average to return the calculated value. How can I archive this?

Related

There a way to auto populate mongodb with mongoose schema?

Okay so my question is this: If i add on to the schema, is there a way auto populate the user if that field doesn't exist?
const mongoose = require('mongoose');
// User Schema
const UserSchema = mongoose.Schema({
email:{
type: String,
required: true
},
username:{
type: String,
required: true
},
password:{
type: String,
required: true
},
registered: {
type: Date,
default: Date.now()
},
currency:{
type: Object,
default: {
cs: 100,
os: 100
}
},
});
const User = module.exports = mongoose.model('User', UserSchema);
Okay, so thats when you register, but say I add a new type after reigstration for example:
test: {
type: String,
default: 'This is a test'
}
So, the use doesn't have this in their db. Is there a way if they do not have this particular field to auto populate if it doesn't exist?

Mongoose access root schema field inside a nested get()

Is it possible to access the root schema field for the get() method. Say if I have schema like so:
const meal = new Schema({
title: String,
options: [options]
});
const options = new Schema({
title: String,
items: [items]
});
const items = new Schema({
title: {
type: String,
get: function(){
return `${this.title} ${meal.title}`
}
},
price: Number,
})
Is it possible to access the meal.title inside items schema's get()?
EDIT:
So I know you can use this.parent() to get the parent schema, but it's not the root one and while in this example I know where the root schema is I could call this.parent().parent().title, however, is there a more dynamic approach?

subdocument with different schemas

I'm new to Mongoose and I'm trying to understand how to properly declare structures.
Say, I have a single collection todos that should contain documents describing what should be done. All TODO items have some properties in common, but most details depend on the specific task.
// Tasks:
var hairCutSchema = new Schema({
style: {type: String, required:true},
length: Number
});
var paintWallSchema = new Schema({
color: {type: String, required:true},
surface: Number, required:true},
layers: Number
});
let napSchema = new Schema({
duration: {type: Number, required:true},
dream: String,
pillows: Number,
// ....
});
// TODOs (parent document):
var todoSchema = new Schema({
due: Date,
created: Date,
task: <either hairCutSchema, paintWallSchema OR napSchema>
});
Of course this isn't really valid code, but I hope it makes my problem clear:
Each todo item should contain exactly one task. There is a limited, well known list of possible tasks and each of them has very specific properties/schema (in my application these subdocuments would be way more complicated).
AFAIK this can't be solved using [subdocuments] because I can only assign one subdocument type per field. Any I need exactly one subdocument anyway, not a list.
An alternative might be something like this:
var todoSchema = new Schema({
due: Date,
created: Date,
hairCutTask: haitCutSchema,
paintWallTask: paintWallSchema,
napTask: napSchema
});
However, this way the schema won't prevent me to declare hairCutTask and napTask at the same time - and probably the required subdocument fields would make each of the three types required anyway.
What is a good way to structure such data and how should the schema look like?
"discriminators" are probably what I'm looking for: http://mongoosejs.com/docs/discriminators.html
From the way this was described I don't see much value in a separate TODO schema. Instead, that information can be included with each task:
var hairCutSchema = new Schema({
due: Date,
created: Date,
style: { type: String, required: true },
length: Number
});
var paintWallSchema = new Schema({
due: Date,
created: Date,
color: { type: String, required: true },
surface: { Number, required:true },
layers: Number
});
let napSchema = new Schema({
due: Date,
created: Date,
duration: { type: Number, required: true },
dream: String,
pillows: Number,
});
You can still easily find tasks by type:
napSchema.find({ pillows: 2 }, function(err, napTasks) {
// ...
});

Performing a Join without using async in mongoose

My Collection looks like:
var followSchema = new Schema({
facebookId: {type: String, required: true},
players : [],
});
here players[] is an array of id's.
The goal is to obtain this array of ids and then for each Id get full profile information from another collection.
In short this requires a join but since joins don't exist I am using async.
Ofcourse
//Step1 : get the players array
FollowModel.findOne({facebookId: req.user.facebookId}, function(err, result) {
//now for each id in the players array call a function which will make another mongoose call and get details
async.map(result.players, gatherPlayerDetails, function(err, results) {
console.log(results);
res.send(results);
});
});
What I don't like about the above solution is that if I am following 200 users, I will make 200 mongoose calls.
If there a way to optimize this query ?
the normal way to do this is populate http://mongoosejs.com/docs/populate.html
in your case:
FollowModel.findOne({facebookId:req.user.facebookId})
.populate('players')
.exec(function(err, result) {
// now your players array is filled with full player objects
....
}
For this to work you need to add a reference type to your schema:
var followSchema = new Schema({
facebookId: {type: String, required: true},
players : [{type: ObjectId, ref: 'User'}],
});

Mongoose query to populate subdocuments from another model

I have seen a few related question on SO, but I can't seem to find the right solution for this problem. Below is a simplified version of my problem:
I have two simple models: user and surf.
The user model has a sub-documents: boards. It also has another property friends that is an array of references to other users.
The surf model has a reference to user as the owner of the surf, friends as a subset of the user's friends (i.e. who of your friends you surfed with), and it also has a reference a board_id, which is part of the user's sub-document described above. I'm not registering the BoardSchema with Mongoose.
All my CRUD operations on user and surf work well. I'm running a query to get all the surfs for a given user's friends when I populate the friends property of the surf as shown in the controller, it works. However, when I try to populate the board_id with name and size I get a mongoose error:
Schema hasn't been registered for model "User.boards"
user model:
// user.model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
/**
* Board Schema
*/
var BoardSchema = new Schema({
name: String,
size: String,
category: String
});
/**
* User Schema
*/
var UserSchema = new Schema({
name: String,
email: { type: String, lowercase: true },
boards: [BoardSchema],
friends: [{type: Schema.Types.ObjectId, ref: 'User'}]
});
module.exports = mongoose.model('User', UserSchema);
surf model
// surf.model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
/**
* Surf Schema
*/
var SurfSchema = new Schema({
user_id: {type: Schema.Types.ObjectId, ref: 'User'},
friends: [{type: Schema.Types.ObjectId, ref: 'User'}],
board_id: {type: Schema.Types.ObjectId, ref: 'User.boards', required: true},
comment: {type: String, required: false},
sessionDate: {type: Date, required: true},
}, {
collection: 'surfs' // Mongoose pluralizes 'surf' to 'surves', so define explicitly
});
module.exports = mongoose.model('Surf', SurfSchema);
surf controller
// surf.controller.js
var mongoose = require('mongoose');
var User = require('../user/user.model')
var Surf = require('./surf.model');
exports.feed = function (req, res) {
var userId = req.user._id;
var userIds = req.user.friends;
Surf
.find({user_id: {$in: userIds}})
.populate('user_id', 'name email')
// .populate('board_id', 'name size')
.populate('friends', 'name email')
.exec(function (err, surfs) {
if (err) {
return handleError(res, err);
}
return res.json(200, surfs);
});
};
The commented out .populate('board_id', 'name size') in the controller is what is causing the issue. I'm not registering the BoardSchema with Mongoose, because it's for a sub-document not a model. Do I need to be? Or is there another way of writing this query to populate the board from that right user's sub-document of boards? Thanks for the help!
Replace the
board: {type: Schema.Types.ObjectId, ref: 'User.boards', required: true},
with
board: {type: Schema.Types.ObjectId, ref: 'UserBoard', required: true},
It should work.
BoardSchema is not for subdocuments. It's for a whole new collection, just like the users collection. All you did is referenced the board documents with the boards property.

Resources