The _id in a subdocument in mongoose schema keeps changing - node.js

I have a model like this:
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
description: {
type: String,
},
package: [
{
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
},
],
});
module.exports = product = mongoose.model('product', productSchema);
and I have created some products in my db. Everytime I fetch a product by its _id I get the package array with varying _id objects in the array. I have to use the ids of the product and a package inside it for comparison and validation purposes but I can't due to the varying nature of the package ids. Is there any way to make it static so it doesn't change just like the product document id?

Related

How to create a new objectID in mongoose schema?

I want to generate two different objectIds in mongoose schema. One for departureLocation and one for arrivalLocation and want to reference it later.
I imported the object id from mongoose like this
let id = new mongoose.Types.ObjectId()
now I want to generate two different object ids like I said above
const routeSchema = new mongoose.Schema(
{
location: {
departureLocation: {
name: {
ref: "Location",
type: String,
required: true,
},
//want to create new object id here,
subLocation: [String],
_id: {
type: String,
},
},
arrivalLocation: {
name: {
ref: "Location",
type: String,
required: true,
},
//want to create new object id here,
subLocation: [String],
_id: {
type: String,
},
},
},
duration: {
type: Number,
required: true,
},
busId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Bus",
required: true,
},
date: {
type: String,
required: true,
},
},
{
timestamps: true,
}
);
MongoDB will automatically create _id for an object in a schema. You do not need to create one. In this schema, there will be 4 automatically generated _ids one for location, one for departureLocation, one for arrivalLocation, and one for the overall schema.

Node mongoose fill createdBy and updatedBy column with userId in every Model save and update

In Node, Mongoose I am trying to achieve something like Laravel's created_by and updated_by columns, these 2 columns are automatically updated by the ORM in every INSERT and UPDATE operation to that particular table.
For example, below is the Material schema, here I want to store the createdBy and updatedBy column with userId whenever any user performs INSERT and UPDATE operations respectively in the materials collection.
I know this can be done while saving the records in particular controller method, but every time in every method I will have to add this and it becomes a pain, so I am looking for a solution where I can define something in the Model itself and it does the job just like the mongoose-delete package.
const mongoose = require('mongoose')
const mongoose_delete = require('mongoose-delete')
const materialSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
type: {
type: String,
required: true,
enum: ['hard', 'soft'],
},
image: {
type: String,
default: null
},
active: {
type: Boolean,
default: true
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
default: null
},
updatedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
default: null
}
}, { timestamps: true })
materialSchema.plugin(mongoose_delete, { deletedAt : true, deletedBy : true, deletedByType: String })
const Material = mongoose.model("Material", materialSchema)
module.exports = Material

How to perform a cascading deleting in MongoDB or Mongoose

I'm working on an e-commerce project in Express and MongoDB. I'm confused with architecture on how to make relationship between two models such that if I delete one element from a table, all of it's associations should be deleted. CASCADE delete, if I'm using the correct term.
I'm not a database designer, just learning Express and MongoDB. So apologies if my schema is not that good.
I have two tables (or documents in MongoDB). One is Order with schema below:
const orderSchema = new mongoose.Schema({
shippingInfo : {
type: mongoose.Types.ObjectId,
ref: 'Address'
},
user : {
type: mongoose.Types.ObjectId,
ref: 'User',
required: true
},
orderItems: [
{
type: mongoose.Types.ObjectId,
ref:'OrderItem'
}
],
totalPrice: {
type: Number,
required: true,
default: 0.0
},
status: {
type: String,
enum: ['processing', 'shipped', 'delivered','cancelled'],
default: 'processing'
},
deliveredAt: {
type: Date,
}
})
and OrderItems
const orderItemSchema = new mongoose.Schema({
product: {
type: mongoose.Types.ObjectId,
ref: 'Product'
},
name: {
type: String,
required: true
},
quantity: {
type: Number,
required: true
},
price: {
type: Number,
required: true
},
image: {
type: String,
required: true
},
})
I want if I delete an Order, all of its OrderItems should be deleted right away (using remove middleware in Order).
I know that Django has something called on_delete=model.CASCADE when we create relationships, but I'm unaware of such thing in Mongoose.
I don't want to explicitly make another API request to search for and delete all OrderItems that are referenced in orderItems array in an Order, once it is deleted. There has to be a better approach for this.
Another post on Stack Overflow suggested that in remove middleware of Order I should do something like
OrderItem.find({ order_id: this._id }).remove().exec();
That would require me to refer order_id in OrderItem right?
And this would create circular dependency since OrderItem would require Order to be created first and vice versa.
What should I do here? Should I change the schema for both tables i.e. remove orderItems entry from Order and instead add order_id in OrderItem? Or is there a Mongoose way to overcome this situation?

Mongoose – querying subdocuments referenced by ID

I have 2 schemas connected like this:
const Brand = new mongoose.Schema({
_id: { type: String, required: true },
name: {
type: String,
required: true,
},
products: [{
type: String,
ref: 'Product',
}],
});
const Product = new mongoose.Schema({
_id: { type: String, required: true },
name: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
});
I want to find brands that have certain types of products, so I wrote a query (not including async/await and promises in the code below for simplicity)
const docs = Brand.find({ 'products.type': 'my-type-here' })
.populate([
{
path: 'products',
},
])
.sort({ index: 1 })
.exec();
This gives me 0 results, yet I know that there are brand with the type of products. What am I doing wrong here? Is it connected with the fact, that products are only referenced by their ids when I invoke find method?

MongoDB database design for products and bundles

I am trying to build an e-commerce website based on Node.js with a mongoDB database and I am encountering problems about some database design or some logic I am missing
To sum up, I have Product that contain price, name, description etc... and Bundle that contains an array of products (by reference). The main problem come when I have to order, I can't get Product AND Bundle together ...
So I have already a Product schema :
const productSchema = new mongoose.Schema({
file: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
preparation: String,
allergics: {
type: Array,
required: true,
},
price: {
type: Number,
required: true,
},
// More fields
});
module.exports = mongoose.model('Product', productSchema);
And a Bundle schema that contains ref to Product (A bundle contains multiple products) :
const bundleSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
itemsId: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Product',
required: true,
}],
description: String,
reduction: {
type: Number,
min: 0,
default: 0,
max: 100,
},
});
module.exports = mongoose.model('Bundle', bundleSchema);
So when a user orders a bundle OR a single product, I use this schema :
const orderSchema = new mongoose.Schema({
orderedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
articlesId: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Product',
},
],
itemsNumber: {
type: Array,
required: true,
},
amount: Number,
orderedAt: Date,
placeToShip: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Place',
},
});
module.exports = mongoose.model('Order', orderSchema);
As you can see, I only reference to Product , but I want to reference to Product AND Bundle , I don't know if this is possible, or if this is the wrong way to design the database like that.
Sorry if the post is a bit long, but I am trying to be as clear as possible! Thanks a lot.
if you want to reference product or bundle(depending on user buys bundle or single product) in articleId, you can do it like this:
Dont give ref in the articleId field of your orderSchema, just specify its type as ObjectId.
const orderSchema = new mongoose.Schema({
...
articlesId: [
{
type: mongoose.Schema.Types.ObjectId
},
],
...
});
And, while populating tell it which model to populate from.
//In case user bought a product
Order.find({findQuery})
.populate({path : '',model : 'Product'})
.exec(function(err,result){...});
//In case user bought a Bundle
Order.find({findQuery})
.populate({path : '',model : 'Bundle'})
.exec(function(err,result){...});
But, you must have a way to find out user bought a single product or a bundle.
Hope that helps you!

Resources