Nodejs mongoose schema many to many relationship with attributes - node.js

I am writing a node express api with mongoose schema. I need to model a many-to-many relationship with additional attributes. My ER would be as following.
A normal many-to-many relationship would be like this:
var UserSchema = new Schema({
id: ObjectId,
username: { type: String, required: true },
...
courses: [ {type : mongoose.Schema.ObjectId, ref : 'Course'} ]
});
var CourseSchema = new Schema({
id: ObjectId,
name: { type: String, required: true },
...
students: [ {type : mongoose.Schema.ObjectId, ref : 'User'} ]
});
How can I model the additional attributes in the User-Course relationship?

Related

How to define schema for personal collection with different type of items with Mongoose and Nodejs

I am creating personal collection web app in which users can create their own collection including different item such as books, whiskey, poststamps... etc. I created schema for this but now i realised i created only for items not for collections. So i need some help to define my collections schema in which users can create different items and some properties of item should be changeable because of item type.For example, I want to store a book collection. I can select (add to standard set of id+name+tags) additional string field “Author”, additional text field “Synopsis”, addition data field “Publication Year”. Maybe with Whiskey or another collection
Here is my DB structure:
User Schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
import bcrypt from "bcrypt";
const userSchema = new Schema(
{
username: { type: String },
email: { type: String, unique: true},
password: { type: String },
role: { type: String, enum:["user", "admin"], default:"user"},
status: {type: String, default:"active"},
collections: [{ type: Schema.Types.ObjectId, ref: 'Collection' }]
},
{ timestamps: true }
);
Collection schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const collectionSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
comments:[{
user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
text: String,
}],
user: [{ type: Schema.Types.ObjectId, ref: "User" }],
likes:[{ type: Schema.Types.ObjectId, ref: 'User' }],
},
{ timestamps: true }
);
collectionSchema.index({'$**': 'text'});
export default model("Collection", collectionSchema);

Is there a way to pass user Id to schema?

I have a user schema and an exam schema, i wanted to pass the id of the user to the schema of the exam
const ExamSchema = new mongoose.Schema({
-----> _id: [{
class: { type: String, required: true },
module: { type: Number,required:true },
date: {type: Date, required: true }
}]
Where it says _id - i wanted it to be the id of the user! Should i do it like this or add the exams schema on the user schema? Like this?
const UserSchema = new mongoose.Schema({
username: { type: String, require: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
active: { type: Boolean, default: true },
exam: [{
class: { type: String, required: true },
module: { type: Number,required:true },
date: {type: Date, required: true }
}]
});
Check Mongoose "Populate"
https://mongoosejs.com/docs/populate.html
A part from the docs,
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
const Story = mongoose.model('Story', storySchema);
const Person = mongoose.model('Person', personSchema);
So far we've created two Models. Our Person model has its stories field set to an array of ObjectIds. The ref option is what tells Mongoose which model to use during population, in our case the Story model. All _ids we store here must be document _ids from the Story model.
In your case just make a user_id in Exam Schema and refer to id of User Schema
const ExamSchema = new mongoose.Schema({
user_id: {type: Schema.Types.ObjectId, ref: 'User' },
class: { type: String, required: true },
module: { type: Number,required:true },
date: {type: Date, required: true }
})

How can i query the data in a sub-document of a document from a sub-document of another document

This is my category schema. For every category document, there is a subdocument of subcategories
#category schema
const CategorySchema = mongoose.Schema({
name: {
type: String, required: true
},
subcategories: [{
name: {
type: String, required: false
},
}],
created : {
type : Date,
default: Date.now()
}
});
let Categories = mongoose.model('categories', CategorySchema);
# selected category schema
const BusinessCategoriesSchema = mongoose.Schema({
business_id: {
type: String
},
category_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "categories",
required: true
},
subcategories: [{
subcategory_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "subcategories._id",
required: false
}
}]
});
let businessCategories = mongoose.model('business-categories', BusinessCategoriesSchema);
How can I retrieve the subcategories sub-document from Categories schema when I perform a query on business-categories collection?
#This is the code snippet I am using but am not getting my desired result
const query = await businessCategories.find({business_id : businessId })
.populate('category_id')
.populate('subcategories.subcategories_id');
I know I am not doing something right.
I was able to get the category name from categories schema but I could not get the subcategories sub-document from the categories schema.
Thank you in advance

Additional fields in a many-to-many relationship

In a user schema, I need to define a field of contacts with a blocked property.
My actual definition goes like this:
const UserSchema = new Schema({
id: Schema.Types.ObjectId,
// Other fields
// ...
contacts: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
}
const UserModel = mongoose.model('User', UserSchema);
From there I was unable to find a possible way to add the blocked field in the same referenced relationship contacts. Is it necessary to create an Intermediary Collection to add the additional field to the relation?
I ended up creating a contact collection which holds at the same time a reference to the user plus the additional fields that I need:
//user.js
const UserSchema = new Schema({
id: Schema.Types.ObjectId,
// Other fields
// ...
contacts: [{
type: Schema.Types.ObjectId,
ref: 'Contact'
}]
}
const UserModel = mongoose.model('User', UserSchema);
//contact.js
const ContactSchema = new Schema({
id: Schema.Types.ObjectId,
contact: {
type: Schema.Types.ObjectId,
ref: 'User'
},
blocked: {
type: Boolean,
required: true
}
}
const ContactModel = mongoose.model('Contact', ContactSchema);

Mongoose many to many relationship with additional data

Product Schema:
var ProductSchema = new Schema({
productName: {type: String, required: true},
});
Client schema:
var ClientSchema = new Schema({
clientName: {type: String, required: true},
products: [{ type : mongoose.Schema.ObjectId, ref : 'Product'}],
});
How can I add additional fields to the relationship? For example add field quantity:
var ClientSchema = new Schema({
clientName: {type: String, required: true},
products: [{ type : mongoose.Schema.ObjectId, ref : 'Product', quantity: Number}],
});

Resources