How can I break this circular dependence between these two javascript modules? - javascript

How can I break the circular dependence between these two modules? Specifically, assignedDoctors: [Doctor.Schema] in the patient model, and assignedPatients: [Patient.Schema] in the doctor model.
/* Patient model */
const mongoose = require('mongoose')
const Notification = require('./notification')
const Appointment = require('./appointment')
const Doctor = require('./doctor')
const Medication = require('./medication')
const PatientSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
required: [true, "Missing user id."]
},
notifications: [Notification.schema],
appointments: [Appointment.schema],
assignedDoctors: [Doctor.schema],
medications: [Medication.schema]
});
const Patient = mongoose.model("Patient", PatientSchema);
module.exports = { Patient };
/* Doctor model */
const mongoose = require('mongoose')
const { Notification } = require('./notification')
const { Appointment } = require('./appointment')
const { Patient } = require('./patient')
const DoctorSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
required: [true, "Missing user id."]
},
specialty: String,
notifications: [Notification.schema],
assignedPatients: [Patient.schema],
appointments: [Appointment.schema],
});
const Doctor = mongoose.model("Doctor", DoctorSchema);
module.exports = { Doctor };
Someone suggested that I can solve it by introducing a third module file, but I am not sure what is it exactly I need to do. Can someone please show me?

Related

Mongoose updating nested subdocuments

I am trying to update sub documents with mongoose using the request.body without passing of the sub documents _id. Updating works but mongoose is removing the _id from the sub documents.
Assume the following schemas
// schemas.js
const mongoose = require('mongoose');
const motorSchema = new mongoose.Schema({
type: String,
volume: Number,
});
const carSchema = new mongoose.Schema({
manufacturer: String,
model: String,
motors: [motorSchema],
});
const userSchema = new mongoose.Schema({
username: String,
email: String,
cars: [carSchema]
});
const mongoose = require('mongoose');
// import schemas
const userSchema = require('userSchema');
const carSchema = require('carSchema');
const motorSchema = require('motorSchema');
// create models
const User = mongoose.model("User", userSchema);
const Car = mongoose.model("Car", carSchema);
const Motor = mongoose.model("Motor", motorSchema);
module.exports.updateCar = async function (request, response) {
const condition = {
_id: new mongoose.Types.ObjectId(request.body.userId),
"cars._id": new mongoose.Types.ObjectIt(request.body.carId)
};
// Build object for partial update
const set = {};
for(let field in reqest.body){
set[`cars.$.${field}`] = request.body[field];
}
const update = {
$set = set;
}
User.findOneAndUpdate(condition, update, {new: true, overwrite: false},
(error, user) => {
if(error) {response.send(error)}
response.json(user);
}
}
The problem is that all my _id properties will be overwritten in the motors array. How can I force mongoose as default to not change the _id properties?
If I understand you correctly, the equivalent mongoDB syntax will use arrayFilters, so you can modify your query to use that as well:
For example:
User.findOneAndUpdate(
condition,
{$set: {"cars.$[item].size": "large"}},
{arrayFilters: [{"item._id": new mongoose.Types.ObjectIt(request.body.carId)}]}
)
See how it works on the playground example
According to this method, your code needs the arrayFilters in the options part and the $[<identifier>] in the $set part of the query:
const set = {};
for(let field in reqest.body){
set[`cars.$[item].${field}`] = request.body[field];
}
const update = {
$set = set;
}
User.findOneAndUpdate(
condition,
update,
{
arrayFilters: [{"item._id": new mongoose.Types.ObjectIt(request.body.carId)}],
new: true, overwrite: false
},
(error, user) => {
if(error) {response.send(error)}
response.json(user);
}

exporting mongoose schema to be used for virtuals

I am trying to export my schema on a separate file to be used for setting virtuals:
const mongoose = require('mongoose');
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true,
toLowerCase: true
},
price: {
type: Number,
required: true,
min: 0
},
category: {
type: String,
enum: ['fruit', 'vegetable', 'dairy'],
toLowerCase: true
}
});
module.exports.Product = mongoose.model('Product', productSchema);
module.exports.productSchema = productSchema
and on a seperate file I want to create my instances using a virtual setter:
const mongoose = require('mongoose');
const { Product, productSchema } = require('./models/product');
mongoose.connect('mongodb://localhost:27017/farmStand', { useNewUrlParser: true })
.then(() => {
console.log('MONGO CONNECTION OPEN.')
}).catch(err => {
console.log('MONGO CONNECTION NOT OPEN!!!');
console.log(err);
});
productSchema.virtual('storeP').set(function (phrase) {
const input = phrase.split(' ');
console.log(input)
const name = input[0];
const price = parseInt(input[1]);
const category = input[2];
this.set({ name, price, category });
this.save();
});
let products = ['peach 1.99 fruit', 'strawberry 1.49 fruit', 'milk 1.99 dairy', 'honey 1.99 dairy', 'spinach 1.99 vegetable']
for (let product of products) {
const p = new Product({});
p.storeP = product
}
when I run the code there is no error but my data will not be stored on my database.
but if I copy my productSchema directly from the first file into the second one, it will be working fine! anything I missing when exporting?

Can't Push data One to Many Relation (nodejs ,mongodb)

I am trying to insert data into MongoDB database but I get this error Cannot read property 'push' of undefined.
I can't understand what is the issue is here in my code. please help me with the solution. I am a Student and learning it.
here I am trying to push service into the category Model. for that, I have created a one to many relations between service and category. but I can't push the services into the category.
Schema design for category & Service =======
const mongoose = require("mongoose")
const Schema = mongoose.Schema
const CategorySchema = new Schema({
name:{
type:String,
required:true
},
services:[
{
type:Schema.Types.ObjectId,
ref:'Service'
}
]
},{ timestamps:true })
const Category = mongoose.model("Cat", CategorySchema);
module.exports = Category;
service======
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const serviceSchema = new Schema({
title:{
type: 'String',
required: true
},
description:{
type: 'String',
required: true
},
image: {
type: 'String',
required: true
},
price: {
type: 'Number',
required: true
},
category: {
type:Schema.Types.ObjectId,
ref:'Cat'
}
})
const Service = mongoose.model("Service", serviceSchema);
module.exports = Service;
here is my service controller
postService:(req, res)=>{
const { title, price, description,category} = req.body;
const image = req.file.filename;
const service = new Service({
title,
price,
category,
description,
image,
});
service.save()
.then((service)=>{
const category = Category.findOneAndUpdate({_id: service.category})
category.services.push(service)
category.save()
console.log(category)
return res.redirect("/admin/services");
})
.catch((err) => {
console.log(err);
return res.redirect("/admin/services/create");
});
},
do like this:
postService: async(req, res)=>{
const { title, price, description,category} = req.body;
const image = req.file.filename;
const service = new Service({
title,
price,
category,
description,
image,
});
try {
await service.save()
let categoryModel = await Category.findById(category);//category should be an ObjectId
categoryModel.services.push(service)
await categoryModel.save()
return res.redirect("/admin/services");
} catch (err) {
console.log(err);
return res.redirect("/admin/services/create");
}
},

How to implement auto increment for mongodb in strapi?

i tried adding these mongoose plugins mongoose-auto-increment and mongoose-sequence to strapi in config/functions/mongoose.js.. the counter collections are getting created.. but the sequence counts are not getting updated.. Is there a way to get these plugins working or is there a way to implement it myself?
// config/functions/mongoose.js
var autoIncrement = require('mongoose-auto-increment');
module.exports = (mongoose, connection) => {
autoIncrement.initialize(mongoose.connection);
var movieSchema = mongoose.Schema({
title: String
}, { collection : 'Tests' });
movieSchema.plugin(autoIncrement.plugin, { model: 'Test', field: 'movieId', startAt: 1 });
};
In a similar situation I solved it using a new Schema as a Counter for the Ids.
Here is the Counter Schema (models/counter.js):
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CounterSchema = Schema({
_id: {
type: String,
required: true
},
sequence: {
type: Number,
default: 0
}
}, {
collection: 'counters'
});
// export the counter model below and call this method to create the first entry in the counter's table
CounterSchema.statics.createFirstIdForMovie = async () => {
const newCounter = new counter({
_id: "movieid",
sequence: 0
});
newCounter.save();
}
And the Movie Schema would be (models/movie.js):
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const MovieSchema = new Schema({
...,
identifier: {
type: Number,
required: false,
unique: true
},
...
});
MovieSchema.pre('save', async function (next) {
// get the next value for the identifier of 'movieid'
if (this.identifier) {
// just editing, don't need to increment or set a new identifier
return;
}
let c = await counter.findById('movieid');
if (!c) {
c = await counter.createFirstIdForMovie();
}
c.sequence += 1;
await c.save();
this.identifier = c.sequence;
});
Hope it helps!
My workaround was to use a single-type as counter.
Each time I need to use and increment the counter I get the counter single-type and use the built-in createOrUpdate service to get the number.
const counters = await strapi.services.counters.find();
const updatedCounter = await strapi.services.counters.createOrUpdate({
ainumber : counters.ainumber + 1,
});
I know single-types are not ment for this, but it works and is easy to handle.
Hope helps someone

Mongoose .Populate() returns empty array

I do not understand what the problem is.
And why each element from the 'tasks' array is null.
Schema = mongoose.Schema;
const userSchema = new Schema({
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
tasks: [{type: Schema.Types.ObjectId, ref: 'Task'}]
}
);
const taskSchema = new Schema({
title: String
});
const User = mongoose.model('User', userSchema);
const Task = mongoose.model('Task', taskSchema);
// Add some default to DB
const task1 = new Task({
title: "Welcome! Here You Can:"
});
const task2 = new Task({
title: "ADD EDIT DELETE SHARE your TASKS "
});
const defaultTasks = [task1, task2];
When create new User I Add defaultTasks
const newUser = {
email: req.body.email,
password: req.body.password,
tasks: defaultTasks
};
Get Users Tasks
app.get('/tasks/', function(req, res){
const email = req.query.user;
User
.findOne({email: email})
.populate('tasks')
.exec()
.then(foundUser => {
console.log(foundUser);
const data = [];
Object.keys(foundUser.tasks).forEach(function(key) {
const val = foundUser.tasks[key];
data.push([val.title, val._id]);
});
res.send(data);
console.log('Data to send ' + data);
});
});
Before .Populate() console.log {
{ tasks: [ 5cf78ac1d08ee617fc89f7ed, 5cf78ac1d08ee617fc89f7ee ]
After { { tasks: [],
Please Help! All that I found did not solve my problem.
Maybe problem in defaultTasks. But i dont see it.
Your code doesn't save your task to DB, it just creates an object. So later when you populate User there are no tasks in DB to be found.
const task1 = await new Task({
title: "Welcome! Here You Can:"
}).save();
// or
const task1 = await Task.create({
title: "Welcome! Here You Can:"
});
P.s. of course you can deal with asynchronous calls the way you want.

Categories