Mongoose get Leagues which has upcoming matches - node.js

I've created a db structure as below. in this structure i would like to retrieve leagues which has matches from currentDate - 7 days and forward. My question is then whether this is possible with the current structure of my database or i need to change that before it is possible?
League schema
var leagueSchema = new Schema({
name: String,
league: Number
});
Match schema
var matchSchema = new Schema({
matchId: Number,
leagueId: Number,
date: Date,
homeName: String,
awayName: String,
});

Your design could use some changes where you create references to documents in other collections for population to be effective. Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s)
In your matchSchema, the league field is set to a number _id, where the ref option is what tells Mongoose which model to use during population, in this case the League model. The following example demonstrates the schema changes:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var leagueSchema = new Schema({
_id: Number,
name: String,
league: Number
});
var matchSchema = new Schema({
_id: Number,
league: { type: Number, ref: 'League' },
date: Date,
homeName: String,
awayName: String
});
var League = mongoose.model('League', leagueSchema);
var Match = mongoose.model('Match', matchSchema);
When you are saving the documents, you simple assign the _id value on your refs, as in the following example:
var premierLeague = new League({ _id: 0, name: 'Premiership', league: 100 });
premierLeague.save(function (err) {
if (err) return handleError(err);
var matchDay = new Date(2015, 10, 7);
var match = new Match({
_id: 1,
date: matchDay,
league: premierLeague._id, // assign the _id from the league
homeName: "Manchester United",
awayName: "West Brom"
});
match.save(function (err) {
if (err) return handleError(err);
// thats it!
});
});
Now on to your query to retrieve leagues which has matches from currentDate - 7 days and forward, you populate your match's league using the query builder:
var oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
Match
.find({ "date": { "$gte": oneWeekAgo } })
.populate('league')
.exec(function (err, matches) {
if (err) return handleError(err);
console.log(matches);
});

Related

how to insert multiple JSON objects to one property of a schema?

I have a requirement to store multiple JSON objects in a property of schema.
take this example...
const Schema = require("mongoose").Schema;
const Student= Schema({
student_id: String,
name:String
attendance:[
{
date: Date,
Status: String
}
]
});
I need to insert attendance of individual student which looks like this..
student_id: student_001,
name:'Joe'
attendance:[
{
date: 24-10-2018,
status: 'Present'
},
{
date: 25-10-2018,
status: 'Absent'
},
//list goes on
]
I am using NodeJs as Backend, EJS template as front end and mongodb database. Date and Status comes when user submits data from front end. So I am having hard time writing my post request. Any types of comments / suggestions / change of model structure are welcome. Thank you.
You can create a separate attendance Schema.
const Schema = require("mongoose").Schema;
const AttendanceSchema = new Schema({
date: Date,
status: String
});
const StudentSchema = new Schema({
student_id: String,
name:String
attendance:[AttendanceSchema]
});
const Student = mongoose.model('Student', StudentSchema);
Add a new Student.
let newStudent = new Student({
student_id: student_001,
name:'Joe'
});
newStudent.save();
Update attendance:
let att1 = {
date: 24-10-2018,
status: 'Present'
};
// Here 'id' is id of particular student.
Student.update({ _id: id }, { $push: { attendance: att1 } })
.then(() => console.log("Success"))
.catch(err => console.log(err));
At some point later:
let att2 = {
date: 25-10-2018,
status: 'Absent'
};
// Here 'id' is id of particular student.
Student.update({ _id: id }, { $push: { attendance: att2 } })
.then(() => console.log("Success"))
.catch(err => console.log(err));
I suggest you to change the model structure to be normalized.
This will improve your experience in future statistics querying.
Also, one more suggestion - do not use string indentifiers in mongoDB, this can cause a headache in maintaining their uniqueness. Mongo has automated _id property assigning to each document, you could use it if you need to indentify any object.
Considering my suggestions - the code will look like:
const Schema = require("mongoose").Schema;
const Student = Schema({
name: String
});
const Attendance = Schema({
date: Date,
status: String,
student_id: {
type: Schema.Types.ObjectId,
ref: 'Student'
}
})
Then, you could simply create attendance records assigned to the student :
const attendance = new AttendanceModel({
date: new Date('05/20/2018'),
status: "present",
student_id: "somestudentid"
});

How to add ID of one mongoose collection to an array in another collection?

I'm trying to add the ID of my category documents to my budget documents. Below is the Schema for my budgets.
var {mongoose} = require('../db/mongoose');
var budgetsSchema = new mongoose.Schema({
year: Number,
categoryIDs: [{type:mongoose.Schema.ObjectId,
ref: 'categories'}]
});
var Budgets = mongoose.model('Budgets', budgetsSchema);
module.exports = {
Budgets
};
And here is the Schema for my categories collection.
var {mongoose} = require('../db/mongoose');
var categorySchema = mongoose.Schema({
name: String,
amount: Number,
sub_categories: [{
name: String,
amount: Number
}]
})
var categories = mongoose.model('categories', categorySchema);
module.exports = {
categories
};
To post categories, I use this express post request to add the categories to the category collection and its ID to the Budget collection.
//The ID is the Budget ID
app.post('/categories/:id', (req, res) => {
var id = req.params.id;
var sub_categories = req.body.sub_categories;
var category = new categories({
name: req.body.name,
amount: req.body.amount,
sub_categories
})
category.save().then((docs) => {
res.send(docs);
console.log(docs)
}).catch((e) => res.status(404).send(e));
Budgets.findById(id).then((docs) => {
if(!docs) {
res.status(404).send();
}
docs.categoryIDs.push(category._id);
}).catch((e) => {
res.send(e).status(404);
})
})
When I run this, it does add the category to the collection, but it does not add the ID to the categoryIDs array in the Budget document. Please help
First, change the model name from Plural to Singular as mentioned in the mongoose docs to avoid confusion:
The first argument is the singular name of the collection your model
is for. Mongoose automatically looks for the plural version of your
model name. Thus, for the example above, the model Tank is for the
tanks collection in the database. The .model() function makes a copy
of schema. Make sure that you've added everything you want to schema
before calling .model()!
So categories to Category and Budgets to Budget. Please verify the new before mongoose.model here, Mongoose docs ref.
var categorySchema = new mongoose.Schema({
name: String,
amount: Number,
sub_categories: [{
name: String,
amount: Number
}]
})

Mongoose remove document with references

I have two Schemas, eventSchema and personSchema as shown below:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var eventSchema = Schema({
title : String,
location : String,
startDate : Date,
endDate : Date
});
var personSchema = Schema({
firstname: String,
lastname: String,
email: String,
dob: Date,
city: String,
eventsAttended: [{ type: Schema.Types.ObjectId, ref: 'Event' }]
});
var Event = mongoose.model('Event', eventSchema);
var Person = mongoose.model('Person', personSchema);
How can I remove all eventsAttended from a deleted Person?
For example, if I remove a Person then I expect that all events assigned to that Person will be removed.
This is my code:
Person.findOneAndRemove({_id: req.body._id}, (err, response) => {
// remove the events assigned to this person
})
With mongoose you can use pre and post middleware on your schemas:
personSchema.post('remove', removeLinkedDocuments);
Then in the removeLinkedDocuments callback, you can remove all linked documents:
function removeLinkedDocuments(doc) {
// doc will be the removed Person document
Event.remove({_id: { $in: doc.eventsAttended }})
}
Note the middleware is only called for the following methods (refer to the linked documentation for details):
count
find
findOne
findOneAndRemove
findOneAndUpdate
update
To remove the documents 'manually' in your callback, you might do
Person.findOneAndRemove({_id: req.body._id}, (err, response) => {
// note that if you have populated the Event documents to
// the person documents, you have to extract the id from the
// req.body.eventsAttended object
Event.remove({_id: { $in: req.body.eventsAttended }}, (err, res) => {
...
})
})

Mongodb store sales data by month schema

How should I defined my schema if I want to retrieve/insert monthly sales figure? like this?
sales: [{
Jan:Number,
Feb:Number
}]
You may simply create a schema as following
var monthlySale = new Schema({
sale: Number,
month: Number, //may be string
year: Number
});
var MonthlySale = mongoose.model('MonthlySale', monthlySale);
and you can insert
var sale = new MonthlySale({ sale: 5000, month: 7, year: 2016})
sale.save(function(err, saleObj) {
if(err)
console.log('Unable to create sale')
else
console.log('New sale created')
});
and you may find as following
MonthlySale.findOne({month: 7, year: 2016}, function(err, sale) {
if(err)
console.log('Unable to fetch sale')
else
console.log('Sale : ', sale)
});
You should not use values as field name in mongodb schema, that makes it hard to query on it. It is upto you what data you want to save, you can save date of each month of the year, or save month and year field separately.
Below are two schema I think you can use.
sales:[
{
month_date: {type: Date},
amount: {type: Number}
}
]
sales:[
{
month: {type: String},
year: {type: Number},
amount: {type: Number}
}
]
With these schema you can easily query on these records
You can use joi validation, here is an example... (Note: i'm making it dynamic by exporting it so that you can use anywhere you want to...)
So, you have to import joi module first. See below...
var joi = require('joi');
Now below is the validators of string, number etc...
var string = joi.string().min(2).max(50); //you can also set max,min..
var bool = joi.boolean();
var number = joi.number().min(1).max(999999999).required();
var object = function object(obj) {
return joi.object().keys(obj);
}
var array = function array(ary) {
return joi.array().items(ary).min(1);
}
Now just export these all...
module.exports = {
string: string,
bool: bool,
number: number,
object: object,
array: array
}
And now you can import the file in which you kept it and can use these validators.
var schema = {
firstname: string.label('user firstname'),
lastname: string.label('user lastname'),
gender: bool.label('user gender'),
age: number.label('user age')
};

Finding Mongoose subdocument by time updated

I have two Mongoose Schemas:
var ItemSchema = new Schema({
trade: {
type: Schema.Types.ObjectId,
ref: 'Trade'
}
});
var Item = mongoose.model('Item', ItemSchema);
and
var TradeSchema = new Schema({
expiresOn: {
type: Date
}
});
var Trade = mongoose.model('Trade', TradeSchema);
I am trying to use Item.find() to find a item if its trade date is less than the date the user passes in via the query string in the request. I'm using the following code:
if (req.query.expiresBefore) {
Item.find({
'trade.expiresOn': {
$lte: req.query.expiresBefore
}
}, function (err, trades) {
console.log(trades)
})
}
However, I am receiving an empty array on the console.log() call. Using $gte also returns an empty array (though my research tells me that I need to use $lte for my purposes). What do I need to do to find the item document by matching the property (expiresOn) of its child (Trade)?
Referring to this one Stackoverflow question, what you want to do is not possible.I am not sure why you set the schemas like this, but if you want to keep them as they are. I would suggest you make a little change like the following
var ItemSchema = new Schema({
trade: {
type: Schema.Types.ObjectId,
ref: 'Trade'
}
});
var Item = mongoose.model('Item', ItemSchema);
and
var TradeSchema = new Schema({
itemId: { //add this
type: Schema.Types.ObjectId,
ref: 'Item'
},
expiresOn: {
type: Date
}
});
var Trade = mongoose.model('Trade', TradeSchema);
if (req.query.expiresBefore) {
Trade.
find({
'expiresOn': {
$lte: req.query.expiresBefore
}
}).
populate('itemId').
exec(function (err, trades) {
console.log(trades)
});
}

Resources