I'm following MVC architecture using express and mongoose and I came upon an issue with circular-dependency. The code itself is written in ES6.
I have these two particular models (keep in mind that I obscured these models as much a possible):
Destination model, which contains information about all available rooms:
// destination.model.js
import mongoose, { Schema } from 'mongoose';
import Booking from './booking.model'; // eslint detect dependency cycle here
import Room from './room.model';
const DestinationSchema = new Schema({
id: { type: Number, required: true },
name: { type: String, required: true, max: 100 },
description: { type: String, required: false },
rooms: [Room.schema]
});
DestinationSchema.statics.getAvailableRooms = async function (startDate, endDate) {
const bookings = await Booking.find({ 'room._id': room._id });
// do something with these bookings
};
export default mongoose.model('Destination', DestinationSchema);
and Booking model, which is in relation many to one with Destination.
// booking.model.js
import mongoose, { Schema } from 'mongoose';
import Destination from './destination.model';
import Room from './room.model';
const BookingSchema = new Schema({
id: { type: Number, required: true },
client: { type: String, required: true },
startDate: { type: Date, default: '' },
endDate: { type: Date, default: '' },
room: { type: Room.schema, required: false },
destination: Destination.schema
});
export default mongoose.model('Booking', BookingSchema);
Main issue:
ESLint detects dependency cycle in destination model (and in booking model) - which is present. The reason for that, is that I have a static method in Destination model, which looks over all Bookings (and possibly might call a static method in the future).
My question (or actually looking for an advice) is, how do I handle this issue? I come from Ruby on Rails background, so I'm really used to having both instance and static methods defined in a model, with single file.
I don't want to separate methods into another file and I would like to keep them in single file - is that possible in any way or should I really go for file separation?
Cheers
I think you should model booking schema like:
const BookingSchema = new Schema({
id: { type: Number, required: true },
client: { type: String, required: true },
startDate: { type: Date, default: '' },
endDate: { type: Date, default: '' },
room: { type: Room.schema, required: false },
destination: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Destination',
},
});
Related
I have the following Schema type called Orders. I am using Arrays of SchemaTypes in some properties. When I save it to the database, it's saving everything fine. I can open the database and see all the data there.
But the problem happens in one property called "files", whenever I try to use find() or findOne() or findById(), this property always comes empty, even if I have data to show.
This is my Schemas:
const statusChildSchema = new Mongoose.Schema({
...
});
const shippingChildSchema = new Mongoose.Schema({
...
});
const fileChildSchema = new Mongoose.Schema({
path: { type: String, required: true, trim: true },
type: { type: String, required: true },
});
const ordersSchema = new Mongoose.Schema(
{
// Relationships
creator: {
type: Mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Users',
autopopulate: false,
},
template: {
type: Mongoose.Schema.Types.ObjectId,
ref: 'Templates',
},
// Common
status: { type: String, trim: true, default: 'new', required: true },
// Child schemas
status_updates: [statusChildSchema],
shipping: [shippingChildSchema],
files: [fileChildSchema],
// Date properties
timings: {
created_at: { type: Date, default: Date.now, required: true },
...
},
},
{ collection: 'Orders', toJSON: { virtuals: true } }
);
Both statusChildSchema and shippingChildSchema is working normally. The problem is only with fileChildSchema. They are very similar, so I don't know what to do. I have researched in Mongoose documents and nothing helpful have been found.
This is the part of my code:
const order = await OrdersModel.findOne({
_id: orderId,
creator: userId,
});
console.log(order.files); // always printing "[]" empty array
I fixed it by installing last version of Mongoose (Version 5.11.8) and restarting everything. Looks like a bug.
I have a field in my mongoose schema called "active" and I wanted to know if there is any way that every date expired in a particular document, then the "active" field would change to false. how should I do that if so, What is the easiest way to do this? else, what is recommended?
And below is my Schema;
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const schema = new Schema({
user_id: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
hash: {
type: String,
required: true
},
active: {
type: Boolean,
},
role: {
type: String,
required: true
},
createdDate: {
type: Date,
default: Date.now
}
});
schema.set('toJSON', { virtuals: true });
module.exports = mongoose.model('User', schema);
You can do this with a feature in mongo called Change Streams that allow you to access real-time data changes. You can subscribe to the changes of a single collection or the whole database and react to them. You can also filter for specific changes or transforms. For your case an example would be something like this.
EDIT: Change streams implementation is only available on replica sets.
const pipeline = [
{ $match: { expire_date: {$lt: Date.now()} } },
{ $set: { active: false } }
];
const collection = db.collection('user');
const changeStream = collection.watch(pipeline);
changeStream.on('change', next => {
// process next document
});
I have two schemas and from each, I want to return a single property.
Here is the schema for a single document or file.
// #ts-check
import { Schema, model } from "mongoose";
const docSchema = new Schema({
name: { type: String, required: true },
approved: { type: Boolean, default: false },
docType: { type: String, required: true },
size: { type: Number, required: true },
bucket: { type: Schema.Types.ObjectId, ref: "Bucket" }
});
docSchema.methods.getSize = function(cb) {
// Return the size of document
};
const Doc = model("Document", docSchema);
export default Doc;
And this is the schema for a bucket of documents
// #ts-check
import { Mongoose, Schema, model } from "mongoose";
const bucketSchema = new Schema({
name: { type: String, required: true, index: true, unique: true },
projectId: { type: String, required: true, index: true },
contractorId: { type: String, required: true, index: true },
Docs: [{ type: Schema.Types.ObjectId, ref: "Document" }]
});
bucketSchema.methods.getSize = function(cb) {
// return the size of all documents that belong to a single bucket
// How do I traverse over the Docs array and use Doc.getSize()???
};
const Bucket = model("Bucket", bucketSchema);
export default Bucket;
Is there a way to do this? I don't want to have to query the database each time I need to get the size of the bucket and then traverse over the results and add the size of each document. I want to make it simple so that basically I call Bucket.getSize() and it returns me the size of the bucket so I can restrict the users from uploading files when they've exceeded a certain limit.
Any help would be appreciated.
Below is my mongoose schema.
An application can have multiple incidents and subscribers. Each incident can have multiple journal updates.
Application->incident(s)->journalupdate(s)
My goal is to allow users to update an incident detail in an application. Later add a journal update to an incident in the application.
const JournalUpdateSchema = mongoose.Schema({
timeStamp: { type: Date, required: true },
owner: { type: String },
updateText: { type: String }
});
// Incident Schema
const IncidentSchema = mongoose.Schema({
incidentNum: { type: String, required: true },
incidentPriority: { type: String, required: true },
description: { type: String, required: true },
jounralUpdates: [JournalUpdateSchema]
});
//Subscriber Schema
const SubscriberSchema = mongoose.Schema({
subscriberName: { type: String },
subscriberMail: { type: String },
subscriberPhone: { type: String }
});
// Application Schema
const ApplicationSchema = mongoose.Schema({
applicationName: { type: String, required: true },
clusterName: { type: String, required: true },
ragStatus: { type: String, required: true },
incidents: [IncidentSchema],
subscribers: [SubscriberSchema]
});
I have already tried Applications.Update(), Applications.findByIdAndUpdate() methods but I cannot reach the incident level to update.
can someone help me with this please? Any help is greatly appreciated.
Thanks.
Im using MongoDb, and I have a workspace schema with mongoose (v4.0.1):
var Workspace = new mongoose.Schema({
name: {
type: String,
required: true
},
userId: {
type: String,
required: true
},
createdOn: {
type: Date,
"default": Date.now
}
});
And a user schema:
var User = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true
},
organisation: {
type: String,
required: true
},
location: {
type: String,
required: true
},
verifyString: {
type: String
},
verified: {
type: Boolean,
default: false
},
password: {
type: String,
required: true
},
createdOn: {
type: Date,
"default": Date.now
},
isAdmin: {
type: Boolean,
default: false
}
});
So the Workspace userId is the ObjectID from the User document.
When Im logged in as an adminstrator, I want to get all workspaces, as well as the email of the user that owns the workspace.
What Im doing is getting very messy:
Workspace.find({}).exec.then(function(workspaceObects){
var userPromise = workspaceObects.map(function(workspaceObect){
// get the user model with workspaceObect.userId here
});
// somehow combine workspaceObjects and users
});
The above doesnt work and gets extremely messy. Basically I have to loop through the workspaceObjects and go retrieve the user object from the workspace userId. But because its all promises and it becomes very complex and easy to make a mistake.
Is there a much simpler way to do this? In SQL it would require one simple join. Is my schema wrong? Can I get all workspaces and their user owners email in one Mongoose query?
var Workspace = new mongoose.Schema({
userId: {
type: String,
required: true,
ref: 'User' //add this to your schema
}
});
Workspace.find().populate('userId').exec( (err, res) => {
//you will have res with all user fields
});
http://mongoosejs.com/docs/populate.html
Mongo don't have joins but mongoose provides a very powerfull tool to help you with you have to change the model a little bit and use populate:
Mongoose population
You have to make a few changes to your models and get the info of the user model inside your workspace model.
Hope it helps