Mongoose reference between attributes - node.js

I have some Schemas in mongoose as follows:
var tournamentSchema = new Schema({
name: {type: String},
teams: [teamSchema],
poules: [pouleSchema],
createdAt: {type: Date, default: Date.now}
})
var pouleSchema = new Schema({
teams: [teamSchema],
createdAt: {type: Date, default: Date.now}
})
var teamSchema = new Schema({
name: {type: String},
createdAt: {type: Date, default: Date.now}
})
I will push some teams in my tournamentSchema. When ready, I want to create the poules with the teams.
Is it possible to make a relation between the 'tournamentSchema.teams' and the 'tournamentSchema.poules'? I think it is not that difficult to push teams in the poules attribute, but when I want to change a name of a team, I want to change it in the poules also. Should I do this manually or is there some relation possible?
Or is this only possible with different Models?
Thank you in advance,
Ronald.

I think mongoose population can help you. Try something like this:
var tournamentSchema = new Schema({
name: {type: String},
teams: [teamSchema],
poules: [pouleSchema],
createdAt: {type: Date, default: Date.now}
})
var pouleSchema = new Schema({
teams: [teamSchema],
createdAt: {type: Date, default: Date.now}
})
var teamSchema = new Schema({
team: {
type: mongoose.Schema.Types.ObjectId,
ref: 'teamsSchema'
}
})
var teamsSchema = new Schema({
name: {type: String},
createdAt: {type: Date, default: Date.now}
})
So every object in your teams array referencing to ObjectId in teamsSchema, and when you change name of team it will automatically affects on teams arrays. Hope it will help you.

Related

How to create a mongoose sub model without creating a collection for it

const walletTransactionSchema = new mongoose.Schema({
a: {type: Boolean, required: true},
},
{timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}});
const walletSchema = new Schema({
b: {type: Boolean, required: true},
transactions: [{type: walletTransactionSchema}],
});
walletSchema.index({'transactions': 1}, {sparse: true});
module.exports.Wallet = mongoose.model('Wallet', walletSchema, 'wallets');
module.exports.WalletTransaction = mongoose.model('WalletTransaction', walletTransactionSchema);
I'm trying to create a model for a subdocument (WalletTransaction) without creating a collection for it. Unfortunately mongoose is automatically creating that collection. How can I prevent that behavior and just define a sub-model without creating a collection. I prefer to organize my schemas by refactoring them instead of just embedding them.
I used to do this without trouble with above definitions. I guess after updating to mongoose 6.0.8 (from 5.13) this is happend.
if you wanna create another model inside a model
You should go with the following approach
const mongoose = require('mongoose');
const userSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
email: {
type: String,
required: true},
about:{type:String},
password: {type: String, required: true},
friends: [new mongoose.Schema({
user: {type: String}
}, {strict: false})],
profileImage: {type: String, default: "default.jpg"},
userName: {type: String, required: true},
matches: {type: Number, default: 0},
wins: {type: Number, default: 0},
losses: {type: Number, default: 0},
backgroundImage: {type: String, default: "default.jpg"},
resetPasswordToken: {type: String, required: false},
resetPasswordExpires: {type: Date, required: false},
isDeleted: {type: Boolean, default: false},
deletedAt: {type: Date, default: null},
}, {timestamps: true}, {strict: false});
module.exports = mongoose.model('User', userSchema);
Like this I create another model in my User model with name Friends in which each entry has one specific id

Translate mongo nested array query into mongoose

I have the following query working with mongo, it returns the expected result
db.getCollection('trainings').find({"sections.employees.employee":ObjectId("5d3afa1a58a7160ea451d1db")})
but when I try the following call with mongoose, it returns an empty array
Training.find({'section.employees.employee': "5d3afa1a58a7160ea451d1db"})
Need some helping to translate the mongo query to mongoose.
If you need anything else just add a comment and I will post here.
It's worth mentioning that I have already tried passing a new ObjectId with the String value, but it also returns an empty array.
Edit: Query usage
return await Training.find({'section.employees.employee': "5d3afa1a58a7160ea451d1db"})
Edit: Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const EmployeeSection = new Schema({
employee: {type: Schema.Types.ObjectId, ref: 'Employee', required: true},
fulfilled: {type: Boolean, default: null},
});
const Section = new Schema({
order: {type: Number, required: true},
date: {type: Date},
employees: {type: [EmployeeSection]},
answers: {type: Number},
hits: {type: Number}
});
const GoalSchema = new Schema({
understanding: {type: Number, required: true},
fixation: {type: Number, required: true}
});
const Evidence = new Schema({
description: {type: String, required: true},
file: {type: String}
});
const Question = new Schema({
participants: {type: Number},
answers: {type: Number},
hits: {type: Number}
});
const TrainingSchema = new Schema({
company: {type: Schema.Types.ObjectId, ref: 'Company', required: true, index: true},
creationDate: { type: Date, default: Date.now },
title: {type: String},
obs: {type: String},
questionNumber: {type: Number},
reference: {type: String},
sections: {type: [Section]},
goals: {
answers: {type: GoalSchema, required: true},
hits: {type: GoalSchema, required: true}
},
evidences: {type: [Evidence]},
questions: {type: [Question]},
area: {type: Schema.Types.ObjectId, ref: 'TrainingArea', required: true},
});
const Training = mongoose.model('Training', TrainingSchema);
module.exports = Training;
I am willing to change the Model schema, if the problem really lays there, but didn't really want to do it.
Why its always a typo?
db.getCollection('trainings').find({"sections.employees.employee":ObjectId("5d3afa1a58a7160ea451d1db")})
Training.find({'section.employees.employee': "5d3afa1a58a7160ea451d1db"})
Forgot s on sections
Made the problem a bit easier for me.
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/training", { useNewUrlParser: true })
const util = require("util")
const Schema = mongoose.Schema;
const EmployeeSection = new Schema({
employee: {type: Schema.Types.ObjectId, ref: 'Employee', required: true}
});
const Section = new Schema({
employees: {type: [EmployeeSection]}
});
const TrainingSchema = new Schema({
sections: {type: [Section]}
});
const Training = mongoose.model('Training', TrainingSchema);
Training.find(
{
"sections.employees.employee": mongoose.Types.ObjectId("5d3afa1a58a7160ea451d1db")
})
.exec()
.then(result => {
console.log(util.inspect(result, false, null, true /* enable colors */))
}).catch(err =>{
console.log(err)
})

Mongoose schema how to add an array

I was wondering how can we add an array of string in a moongoose schema.
I have the following code but it is not working:
var message = new Schema({
topic: String,
content: String,
restriction:String,
sender:String,
reciever:String,
users:[String],
read:{type: String, default: 'no'},
like:{ type: Number, default: 0 },
created_at: {type: Date, default: Date.now}
});
I am talking about users. Can you help?
Cobbling together what you said in your comments and the main post, I can't help but think you're missing the modeling step of mongoose.
First you define the schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
var MessageSchema = new Schema({
topic: String,
content: String,
restriction:String,
sender:String,
reciever:String,
users:[String],
read:{type: String, default: 'no'},
like:{ type: Number, default: 0 },
created_at: {type: Date, default: Date.now}
});
Then you have to tell mongoose about it:
const Message = mongoose.model('Message', MessageSchema);
Then you can create an instance to put data into:
mongoose.connect('mongodb://localhost:27017/mydb'); // assuming that's a working mongo instance
let message = new Message();
message.users.push('Juliana');
message.save((e,u) => { console.log('New user saved!'); });
If I'm wrong, please post more info about what's not working.
var message = new Schema({
topic: String,
content: String,
restriction:String,
sender:String,
reciever:String,
users:[{
type: String
}],
read:{type: String, default: 'no'},
like:{ type: Number, default: 0 },
created_at: {type: Date, default: Date.now}
});
try this
var message = new Schema({
topic: String,
content: String,
restriction:String,
sender:String,
reciever:String,
users:[
{name: String}],
read:{type: String, default: 'no'},
like:{ type: Number, default: 0 },
created_at: {type: Date, default: Date.now}
});

Multiple one-to-many relationship on mongoose

I'm using mongoose to store three models of documents, sometimes I have to update references between then, for this I'm using mongoose-relationship plugin,
My need is reference then like this:
One customer have many schedules,
One costumer have many orders,
One order have many schedules
When I create an order I need to push schedules id's into order to reference then. But I can only reference one childPath per collection, my models are mapped like this;
Customers:
var CustomerSchema = new Schema({
name: {type: String, required: true},
email: {type: String, required: true},
shedules: [{ type:mongoose.Schema.Types.ObjectId, ref:"Schedule" }],
orders: [{ type:mongoose.Schema.Types.ObjectId, ref:"Order" }]
}
Schedules:
var ScheduleSchema = new Schema({
customer: {type:mongoose.Schema.Types.ObjectId, ref:"Customer", childPath:"shedules"}, //shedule id
order: {type:mongoose.Schema.Types.ObjectId, ref:"Order", childPath:"shedules"}, //order Id
sequence: {type: Number, default: 0},
creation_date: {type: Date, default: Date.now}
}
SheduleSchema.plugin(relationship, {relationshipPathName:['customer','order']});
Orders:
var OrderSchema = new Schema({
customer: {type:mongoose.Schema.Types.ObjectId, ref:"Customer", childPath:"order"},
shedules: [{type:mongoose.Schema.Types.ObjectId, ref:"Shedule" }],// <-- this field doesn't update.
price: {type: Number, default: 0}
}
OrderSchema.plugin(relationship, { relationshipPathName:'customer' });

about mongoose populate relation a string field

I have two Schema
1 - User
UserSchema = new db.Schema({
email: {type: String, required: true},
pass: {type: String, required: true},
nick: {type: String, required: true},
admin: {type: String, default: ''},
reg: {type: Date, default: Date.now}
});
2 - Article
ArticleSchema = new db.Schema({
title: {type: String, required: true},
alise: {type: String},
time: {type: Date, defaults: Date.now},
view: {type: Number, defaults: 0},
author: {type: String},
content: {type: String},
classes: {type: db.Schema.Types.ObjectId, ref: 'Classes'},
user: {type: String, ref: 'User'}
});
I want ArticleSchema user field relation UserSchema nick.
my code:
Model.findOne({}).populate('classes user').exec(function(err, res){
if(err){
cb(err);
}else{
cb(null, res);
}
});
This is not working
message: 'Cast to ObjectId failed for value "tudou" at path "_id"'
What should I do?
Apparently you are using Mongoose, right?
If yes, to do it you must use db.Schema.Types.ObjectId in the ArticleSchema user field. So, your ArticleSchema should looks like this:
ArticleSchema = new db.Schema({
title: {type: String, required: true},
alise: {type: String},
time: {type: Date, defaults: Date.now},
view: {type: Number, defaults: 0},
author: {type: String},
content: {type: String},
classes: {type: db.Schema.Types.ObjectId, ref: 'Classes'},
user: {type: db.Schema.Types.ObjectId, ref: 'User'}
});
According to documentation:
There are no joins in MongoDB but sometimes we still want references to documents in other collections. This is where population comes in.
So, taking a look here, we can do something like that:
//To create one user, one article and set the user whos created the article.
var user = new UserSchema({
email : 'asdf#gmail.com',
nick : 'danilo'
...
});
user.save(function(error) {
var article = new ArticleSchema({
title : 'title',
alise : 'asdf',
user : user,
...
});
article.save(function(error) {
if(error) {
console.log(error);
}
});
}
And to find an article that was created for danilo:
ArticleSchema
.find(...)
.populate({
path: 'user',
match: { nick: 'danilo'},
select: 'email nick -_id'
})
.exec()
I suggest you to read about mongoose populate here
As of 4.5.0 You can use populate virtuals : http://mongoosejs.com/docs/populate.html#populate-virtuals
UserSchema = new db.Schema({
email: {type: String, required: true},
pass: {type: String, required: true},
nick: {type: String, required: true},
admin: {type: String, default: ''},
reg: {type: Date, default: Date.now}
});
ArticleSchema = new db.Schema({
title: {type: String, required: true},
alise: {type: String},
time: {type: Date, defaults: Date.now},
view: {type: Number, defaults: 0},
author: {type: String},
content: {type: String},
classes: {type: db.Schema.Types.ObjectId, ref: 'Classes'},
user: {type: String}
});
ArticleSchema.virtual('_user', {
ref: 'User', // The model to use
localField: 'user', // Find people where `localField`
foreignField: 'email', // is equal to `foreignField`
// If `justOne` is true, 'members' will be a single doc as opposed to
// an array. `justOne` is false by default.
justOne: true,
options: { sort: { name: -1 }, limit: 5 }
});
var User = mongoose.model('User', UserSchema);
var Article = mongoose.model('Article', ArticleSchema);
Article.find({}).populate('_user').exec(function(error, articles) {
/* `articles._user` is now an array of instances of `User` */
});

Resources