mongo db schema relational or in collection - mongodb

I am working on a side project at the moment that will hopefully help understand Mongo. I am coming from a MySQL world so some of the concepts are a bit strange to me at minutes.
My side project is essentially a project organiser, a project can have 3 areas where a a user can upload multiple files/images, project assests, work in progress, and deliverables.
So should I be creating collections for assets, wip and deliverables and then link them to the project? Using some like,
type: Schema.Types.ObjectId,
ref: "projects"
Or should they be part of the projects schema giving each file a type instead making the project schema look something like,
// Create schema
const ProfileSchema = new Schema({
name: {
type: String,
required: true
},
owner: {
type: Schema.Types.ObjectId,
ref: "users"
},
slug: {
type: String,
required: true,
max: 40
},
status: {
type: String,
required: true
},
brief: {
type: String,
default: "No brief given"
},
date_due: {
type: Date
},
created_at: {
type: Date,
default: Date.now
},
files: [
name: {
type: String
},
filepath: {
type: String
},
type: {
type: String
}
]
});
Potentially there will be 1000s of rows in the collection if I were to ever launch the tool
Is there an accepted way of doing what would ordinarily be an 1:n relationship in a relational database?

Related

Moongose: .populate on key with white space doesn't work

I'm using Express and Mongoose to do some database actions. When trying to populate a path where the key includes a whitespace, it basically get's ignored.
MongoDB Model:
const OrgCrimeSchema = new Schema({
gracePeriod: { type: Date, default: Date.now() },
Technical: {
description: String,
difficulty: Number,
owner: { type: Schema.Types.ObjectId, ref: 'User' },
},
'Social Engineering': { // This one causes issues
description: String,
difficulty: Number,
owner: { type: Schema.Types.ObjectId, ref: 'User' },
},
});
Find + Populate:
const now = Date.now();
const allOrgCrimes = await OrgCrime.find({ gracePeriod: { $lte: now } })
.populate('Technical.owner', 'name')
.populate('Social Engineering.owner', 'name');
console.log(allOrgCrimes['Social Engineering'][0].owner);
//5fca3b4a86e77b5c8e58b683
console.log(allOrgCrimes['Technical'][0].owner);
// { name: 'npc_alice', _id: 5fae6d7ee60018434108369c }
I assume the path is not being populated because of a white space in the key. I've tried both dot notation and typing {path: 'Social Engineering', select: 'name -id'}, without luck.
Is there any way around this without having to rewrite the schema structure?
In short, there is no way, if we wanted to populate multiple paths at the same time there is this way
for exmaple
Story
.find(...)
.populate('book author') // space delimited path names
.exec()
you can see space delimited path names.
When you pass a key with space,mongoose consider it as populate multiple
As poined out by Mohammad Yaser Ahmadi, there is no solution to this issue today because of populate assumes you're populating multiple instead of trying to read a path name with a space in between. How I 'solved' this was to rewrite the model to this:
const OrgCrimeSchema = new Schema({
gracePeriod: { type: Date, default: Date.now() },
roles: [{
role: String,
description: String,
difficulty: Number,
owner: { type: Schema.Types.ObjectId, ref: 'User' },
}]
})
And then the populate actually get's easier:
.populate('roles.owner', 'name')

How to give iDs to dynamic fields in React-Redux?

I created a simple dynamic fields in React-Redux with a plus button to add as many field as I want (hobbies) of an already existing form. I'm using mongodb as a database and so I have this error that tells me that my fields/data don't have iDs.
so how can I generate iDs for my data?
this below is my model with featherJs. as you can see this is how I added my hobbies array in the existing model called myService. I can see that my hobbies are created in mongo (using Robo 3T) which is great but i'm having difficulty reusing them (hobbies) in an other component in Redux. I'm not sure if I should give IDs to this fields or create a new service just for them. I never coded something in backend so I'm confused. what's the rule for this kind of situations.
Any other suggestions would be helpful.
warning in Redux: Each child in a list should have a unique "key" prop.
error in api : Cast to ObjectId failed for value at path "_id" for model "
const { Schema } = mongooseClient;
const myService = new Schema({
type: { type: String, enum: VALID_TYPES, required: true },
user: {
type: mongooseClient.Schema.Types.ObjectId,
ref: 'user',
required: true
},
comment: String,
hobbies: [{
type: mongooseClient.Schema.Types.ObjectId,
ref: 'hobbies',
default: [],
required: false }],
date: {
begin: { type: Date, default: Date.now },
current: { type: Date, default: Date.now },
end: { type: Date, required: true },
},
}, {
timestamps: true
});
return mongooseClient.model('myService', myService);
};

Data modelling using mongoose for sports bet tracking application

I built a simple sports bet tracker application while I am learning the MERN stack. Users can track their sports bets and see various stats on their performance. It currently only supports tracking single bets (1 selection in bet) and I wish to add to ability to track multiple bets (>1 selections in bet). Each selection in a multiple bet will have the same data as a single bet eventDate, sport, event, selection odds etc. I'm just looking for some advice on the best way to add this in. Bet model currently is as follows
const betSchema = mongoose.Schema({
eventDate: {
type: Date
},
sport: {
type: String
},
event: {
type: String
},
market: {
type: String
},
selection: {
type: String
},
odds: {
type: Number
},
result: {
type: String,
default: 'Pending'
},
stake: {
type: Number
},
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
}
}, {
timestamps: true
})
Going forward a bet can have one selection or many in it so I was thinking this should become an array. If it has one selection the odds for the bet will be the odds of that selection but if it has multiple selections in it the odds of the bet will be the odds of the selections multiplied. If one selection in a multiple bet loses the bet is a loss. I was thinking something like the following setup but I'm not sure as I don't have much database experience any help who'd be appreciated.
const betSchema = mongoose.Schema({
selections: [{
sport: {
type: String
},
event: {
type: String
},
eventDate: {
type: Date
},
market: {
type: String
},
selection: {
type: String
},
result: {
type: String
},
odds: {
type: Number
},
}],
odds: {
type: Number
},
stake: {
type: Number
},
result: {
type: String,
default: 'Pending'
},
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
}
}, {
timestamps: true
})
I went with the Schema shown in the question, not sure if it's the best solution but it works for what I am trying to build.

database design for a market

I want to design database for a market with simple and few objects for selling using NodeJS, MongoDB and Mongoose. Because I'm new to MongoDB and NoSQL designs, I need a guide for designing it.
My implementation is here:
var orderSchema = new Schema({
orderId: Schema.Types.ObjectId,
orderType: {
type: String, enum: ['OBJEC1',
'OBJECT2',
//other objects
], default: 'ALBUM'
},
price: { type: String, enum: ['PRICE1', 'PRICE2', 'PRICE3'] },
coverPhoto: { type: String, default: '' },
photos: [{
address: { type: String, default: 'media/uploads' },
}],
orderQuantity: { type: Number, default: 1 },
isChecked: { type: Boolean, default: true },
date: { type: Date, default: Date.now }
});
Besides, I'll save reference of each order to its related user. Am I right, or not? Thanks a lot.
The way you designed your schema based on the logic seems good. One thing is you have used default in all the fields.
First, you should understand that default is optional and default is used only when you want to populate some value during the data is created.
Example: you have default for date field, here it is good to have. You don't want to manually assign a date during processing the data. So only unless your field should have common default value when creation then you go ahead otherwise remove the default field and make sure the data is inserted properly.
you can use required attribute in case some field is mandatory to create a document in the collection. I guess orderType a mandatory field so don't miss it ever during insertion so make it as required: true.
var orderSchema = new Schema({
orderId: {
type: Schema.Types.ObjectId
},
orderType: {
type: String,
enum: ['OBJEC1','OBJECT2']
},
price: {
type: String,
enum: ['PRICE1', 'PRICE2', 'PRICE3']
},
coverPhoto: {
type: String
},
photos: [{
address: {
type: String
}
}],
orderQuantity: {
type: Number
},
isChecked: {
type: Boolean,
default: true
},
date: {
type: Date,
default: Date.now
}
});

Modelling many-to-many relationships in MongoDB

I am having difficulty coming up with schemas for a school app.
In particular, I am trying to model the relationship between the different kinds of users (e.g. instructors, teaching assistants, and students) with the courses and tutorials that they belong to.
Here are my requirements:
each course will have one to many tutorials;
each course will be taught by one to many instructors;
each course will have one to many students;
each tutorial will have one to many teaching assistants;
each instructor will teach one to many courses;
each teaching assistant may have one to many tutorials in one to many course;
each student will be enrolled in one to many courses;
each student may belong to one tutorial in the course that they are enrolled in;
So far, the following are my schemas for the user, course, and tutorial collections.
var CourseSchema = new mongoose.Schema({
name: { type: String, required: true },
code: { type: String, required: true },
tutorials: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Tutorial' }], // 1
instructors: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }], // 2
students: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }] // 3
});
var TutorialSchema = new mongoose.Schema({
number: { type: String, required: true },
teachingAsst: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }] // 4
});
var UserSchema = new mongoose.Schema({
email: { type: String, lowercase: true },
password: String,
name: {
first: { type: String, lowercase: true },
last: { type: String, lowercase: true }
},
roles: [String] // instrutor, teachingAsst, student
};
The problem lies with my requirements 5 to 8 -- which is more so the relationship from the User to the other models. What could be a good way to model these relationships?
One way, I thought of doing it e.g. req 5 was to add a field to the User schema
instructor: {
courses: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Course' }]
}
But the problem happens when I do e.g. req 6. similarly because it will complicate the queries (e.g. "find all the tutorials in a course that the user is a teaching assistant in").
teachingAsst: {
courses: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Course' }]
tutorials: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Tutorial' }]
}
In your case, Design is many to many relations. So you have two approach for your problem.
Reference Document
Embedded Document
Embedded approach will have duplicate data which is difficult to update and delete where as the read operation will be much efficient due to single query.
In case of the Reference Approach, your data will be demoralized. So, update and delete operation will be easy where as the read operation will have multiple hits on the database.
So, based on the your application requirement you should have to decide the appropriate approach.