How to create mongoose schema for category sub category management? - mongodb

MongoDB Schema for handling category subcategory management where you can have multiple of subcategories from one root category. Basically for e-commerce system where user can add a product by selecting a category.
I have some requirements like:
Fast retrieval of data from DB and easy insertion.
Please change according to you
import mongoose from 'mongoose';
const {Schema} = mongoose;
import slug from 'slug';
import shortid from 'shortid';
const categorySchema = new Schema({
slug: {
type: String,
required: true,
unique: true,
},
isDelete: {
type: Boolean,
default: false
},
}, {
timestamps: true
});
categorySchema.pre('validate', function (next) {
if (!this.slug) {
this.slugify();
}
next();
});
categorySchema.methods.slugify = function () {
this.slug = slug(this.firstName) + '-' + shortid.generate();
};
export default mongoose.model('category', categorySchema);
Please don't send any link to mongoDb docs

Related

How can I see the products per each category with mongoose

this is my schema for storing products using mongoose as below.
const mongoose = require("mongoose");
const mongoosePaginate = require("mongoose-paginate-v2");
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
},
productImage: {
type: String,
required: true,
},
description: {
type: String,
},
createdAt: {
type: Date,
default: new Date(),
},
deletedAt: {
type: Date,
},
});
productSchema.plugin(mongoosePaginate);
const productModel = mongoose.model("Product", productSchema, "Product");
module.exports = productModel;
and this how I have the schema for storing categories that products are related to
const mongoose = require("mongoose");
const categorySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
product: { type: mongoose.Schema.Types.ObjectId, ref: "Product" },
});
const categoryModel = mongoose.model("Category", categorySchema, "Category");
module.exports = categoryModel;
What I don´t know is how to populate my controller.
getAll: async (req, res) => {
const limitPage = parseInt(req.query.limit, 10) || 10;
const pageChange = parseInt(req.query.page, 10) || 1;
Product.paginate({}, { limit: limitPage, page: pageChange })
.then((result) => {
return res.status(200).json({
message: "GET request to all getAllProducts",
dataCount: result.length,
result: result,
});
})
.catch((err) => {
console.log(err);
res.status(500).json({
error: err,
});
});
},
Please help, I don´t understand why it not being populated and how to see the categories displayed with the categorie they belong to.
You should probably include populate in your query like so:
...
Product.paginate({}, { limit: limitPage, page: pageChange }).populate('category')
...
Note: Are you sure you want to have a 1-1 relation between products and categories. Because this is what you achieve if you set the relation like you did on both schemas. If yes, you should find a way to ensure that this 1-1 relation is enforced each time you save or update objects.

Populate an array in Mongoose

I am building a search query for training sessions that will return me return details of a session, populating data from the coach (ObjectId) and the participants (Array of ObjectIds). I can populate the coach but I can not populate the participants. My session schema is:
const mongoose = require('mongoose');
import { timestamp } from "./plugins/timestamp"
import { User } from './index'
const SessionSchema = new mongoose.Schema({
coach: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
title: { type: String, required: true, default: "Lacrosse Training Session" },
participants: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }]
});
SessionSchema.plugin(timestamp);
export const Session = mongoose.model('Session', SessionSchema);
And I am trying to populate with:
const session = await Session.findById(req.params.id).populate('coach').populate('participants');
Output
When I use only populate('coach'), I get something like:
coach: {address: {city: "Joes"}, name: "John John", …} <= <= <= POPULATED
participants: ["5ea43590f105a4188358210f", "5ea43590f105a4188358210e", "5ea43590f105a41883582115"]
But when I use populate('coach').populate('participants'), I get the same coach, but empty participants (participants: [])
Why is that? How can I populate each element of the participants array?
Thank you
you can use one of the following:
1-
const session = await Session.findById(req.params.id).populate([{ path: 'coach' }, { path: 'participants' }])
2-
const session = await Session.findById(req.params.id).populate({ path: 'coach' }).populate({ path: 'participants' });
also make sure that these participants Ids are already exist in the User collection

Fetch user details based on userId which is referenced field in userDetails table

Database: MongoDB
Backend: Node.js
There are two tables in the database: User and userDetails. ObjectId in User table has been used as a reference in userDetails table as userId. Now based on this userId I want to display userDetails.
I have tried to make a function and tried to test that in postman but I get null data. When I test this function in api testing tool postman, I don't get any user Details. I am not able to understand why I am not getting any data.
Here is the function:
function getUserDetailByUserId(req, res) {
userDetails.find(req.params.userId, (error, detail) => {
if (error)
res.send(error);
res.json(detail);
}).populate(userId);
}
use ObjectId
new mongoose.mongo.ObjectID(req.params.userId)
function getUserDetailByUserId(req, res) {
userDetails.findOne({userId: new mongoose.mongo.ObjectID(req.params.userId)})
.populate(userId)
.exec(function(error, detail){
if (error)res.send(error);
res.json(detail);
});
}
userDetail Schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
const userDetailSchema = new Schema({
dateOfBirth: {
type: Date,
required: true
},
gender: {
type: String,
required: true
},
country: {
type: String,
required: true
},
interest: {
type: String,
required: true
},
remarks: {
type: String,
},
userId: {
type: Schema.Types.ObjectId, // Referencing the Registered Users in User Model by their ObjectId reference.
ref: 'User' // Creating a relation between User and UserDetails Model through unique ObjectId.
}
});
module.exports = mongoose.model('UserDetails', userDetailSchema);

Mongoose populate array

I can't get mongoose to populate an array of objects.
The schema is as follows:
var topOrganisationsForCategorySchema = new mongoose.Schema({
category: String,
topOrganisations: [{
organisation: {
type: mongoose.Schema.Types.ObjectId,
ref: 'organisation'
},
model: mongoose.Schema.Types.Mixed
}]
});
module.exports = mongoose.model('topOrganisationsForCategory', topOrganisationsForCategorySchema);
I would like all of the objects in this collection populated with an array of organisations.
Here is what i have tried
TopOrganisationsForCategory
.find()
.exec(function(err, organisation) {
var options = {
path: 'topOrganisations.organisation',
model: 'organisation'
};
if (err) return res.json(500);
Organisation.populate(organisation, options, function(err, org) {
res.json(org);
});
});
var organisationSchema = new mongoose.Schema({
name: String,
aliases: [String],
categories: [String],
id: {
type: String,
unique: true
},
idType: String
});
organisationSchema.index({
name: 'text'
});
module.exports = mongoose.model('organisation', organisationSchema);
You're close but a couple notes:
The following code assumes you also have a schema/model declaration for Oranisation.
I am not sure if the model property is meant as an option (which would be invalid) or actually is a property of topOrganisations.
So, I left model in as it shouldn't cause any issues but be aware that if you were using it as an option it is not doing what you might think it is.
// Assuming this schema exists
var organisationSchema = new mongoose.Schema({...});
var topOrganisationsForCategorySchema = new mongoose.Schema({
category: String,
topOrganisations: [{
organisation: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Organisation' // Model name convention is to begin with a capital letter
}
// Is `model` supposed to be for the ref above? If so, that is declared in the
// Organisation model
model: mongoose.Schema.Types.Mixed
}]
});
// Assuming these model definitions exist
var Organisation = mongoose.model('Organisation', organisationSchema);
var TopOrganisationsForCategory = mongoose.model('TopOrganisationsForCategory', TopOrganisationsForCategorySchema);
// Assuming there are documents in the organisations collection
TopOrganisationsForCategory
.find()
// Because the `ref` is specified in the schema, Mongoose knows which
// collection to use to perform the population
.populate('topOrganisations.organisation')
.exec(function(err, orgs) {
if (err) {
return res.json(500);
}
res.json(orgs);
});

Does Mongoose Actually Validate the Existence of An Object Id?

I like the validation that comes with Mongoose. We are trying to figure out whether we want to use it, and put up with the overhead. Does anyone know if providing a reference to the parent collection when creating a mongoose schema, (in the child schema, specify the object id of the parent object as a field,) does this then mean that every time you try to save the document it checks the parent collection for the existence of the refereneced object id?
I'm doing it with middleware, performing a search of the element on validation:
ExampleSchema = new mongoose.Schema({
parentId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Example'
}
});
ExampleModel = mongoose.model('Example', ExampleSchema);
ExampleSchema.path('parentId').validate(function (value, respond) {
ExampleModel.findOne({_id: value}, function (err, doc) {
if (err || !doc) {
respond(false);
} else {
respond(true);
}
});
}, 'Example non existent');
I'm using mongoose-id-validator. Works good
var mongoose = require('mongoose');
var idValidator = require('mongoose-id-validator');
var ReferencedModel = new mongoose.Schema({name: String});
var MySchema = new mongoose.Schema({
referencedObj : { type: mongoose.Schema.Types.ObjectId, ref: 'ReferencedModel'},
referencedObjArray: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ReferencedModel' }]
});
MySchema.plugin(idValidator);
No, an ObjectId field that's defined in your schema as a reference to another collection is not checked as existing in the referenced collection on a save. You could do it in Mongoose middleware, if needed.
I found this thread very helpful and this is what I came up with:
This Middleware (I think its one anyway please let me know if not) I wrote checks the referenced model for the id provided in the field.
const mongoose = require('mongoose');
module.exports = (value, respond, modelName) => {
return modelName
.countDocuments({ _id: value })
.exec()
.then(function(count) {
return count > 0;
})
.catch(function(err) {
throw err;
});
};
Example model:
const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const Schema = mongoose.Schema;
const User = require('./User');
const Cart = require('./Cart');
const refIsValid = require('../middleware/refIsValid');
const orderSchema = new Schema({
name: { type: String, default: Date.now, unique: true },
customerRef: { type: Schema.Types.ObjectId, required: true },
cartRef: { type: Schema.Types.ObjectId, ref: 'Cart', required: true },
total: { type: Number, default: 0 },
city: { type: String, required: true },
street: { type: String, required: true },
deliveryDate: { type: Date, required: true },
dateCreated: { type: Date, default: Date.now() },
ccLastDigits: { type: String, required: true },
});
orderSchema.path('customerRef').validate((value, respond) => {
return refIsValid(value, respond, User);
}, 'Invalid customerRef.');
orderSchema.path('cartRef').validate((value, respond) => {
return refIsValid(value, respond, Cart);
}, 'Invalid cartRef.');
orderSchema.path('ccLastDigits').validate(function(field) {
return field && field.length === 4;
}, 'Invalid ccLastDigits: must be 4 characters');
orderSchema.plugin(uniqueValidator);
module.exports = mongoose.model('order', orderSchema);
I'm a very new dev so any feedback is greatly valued!
You can try https://www.npmjs.com/package/lackey-mongoose-ref-validator (I'm the developer)
It also prevents deletion if the reference is used on another document.
var mongooseRefValidator = require('lackey-mongoose-ref-validator');
mongoSchema.plugin(mongooseRefValidator, {
onDeleteRestrict: ['tags']
});
It's an early version, so some bugs are expected. Just fill in a ticket if you find any.
I know this is an old thread but I had the same problem and I came up with a more "modern" solution.
I'm not an expert myself, hope I'm not misleading anyone, but this seems to work:
for example, in a simple "notes" schema, which contains a user field:
const noteSchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: 'User' },
text: String
});
here's the middleware that checks if the userId exists:
noteSchema.path('user').validate(async (value) => {
return await User.findById(value);
}, 'User does not exist');