here is the product model:
const productSchema= new schema({
_id: {
type: String,
default: () => {return uniqid().toUpperCase()}
},
name: {
type: String
},
price: {
type: Number
},
type: {
type: String
},
category: {
type: String
},
sub_category: {
type: String
},
images: {
type: Array
},
sizes: {
type: Array,
default: ['OS']
},
materials: {
type: Array
},
description: {
type: String
},
weight: {
type: String,
default: ''
}
});
and here is the orders model:
let orderSchema = new schema({
products: [productModel],
});
in the product model, there is no quantity entry, but I need to pass the quantity of each product that is sent to the orders Api without changing product model.
example of api call:
{
"products": [{
"images": [
"1",
"2",
"3"
],
"sizes": [
"OS"
],
"materials": [
"Cotton"
],
"weight": "",
"_id": "3EC65ISJWW6LU8C",
"name": "Tshirt",
"price": 10.99,
"type": "Clothing",
"category": "Men Tshirts",
"description": "A Tshirt",
"quantity": 5
},{
"images": [
"upload_7eb7af15fdaf27bff7667ee35ae4a8b0.png",
"upload_7dea46a64b046f2d71a75612aaba1523.png",
"upload_13422483a3b7406620b8e16c0d0ed7df.png"
],
"sizes": [
"OS",
"Os2"
],
"materials": [
"Cotton",
"M2"
],
"weight": "",
"_id": "3EC65ISJWW6LVLM",
"name": "T-Shirt",
"price": 10.99,
"type": "Clothing",
"category": "Men Tshirts",
"description": "A Tshirt",
"quantity": 5
}]
}
So I added the quantity entry but it's not in the product model.
here is how I did it but it's not working:
products: [productModel, {quantity: Number}],
You can use mongoose discriminators for this to extend the base schema
Go through this doc for further details
https://mongoosejs.com/docs/api.html#model_Model.discriminator
Here is a sample example as described in the doc
function BaseSchema() {
Schema.apply(this, arguments);
this.add({
name: String,
createdAt: Date
});
}
util.inherits(BaseSchema, Schema);
var PersonSchema = new BaseSchema();
var BossSchema = new BaseSchema({ department: String });
var Person = mongoose.model('Person', PersonSchema);
var Boss = Person.discriminator('Boss', BossSchema);
new Boss().__t; // "Boss". `__t` is the default `discriminatorKey`
var employeeSchema = new Schema({ boss: ObjectId });
var Employee = Person.discriminator('Employee', employeeSchema, 'staff');
new Employee().__t; // "staff" because of 3rd argument above
Related
const mongoose = require("mongoose");
const productSchema = mongoose.Schema({
product_name: {
type: String,
required: [true, "Must Enter Product Name"],
},
product_brand: {
type: String,
},
category: {
type: String,
required: [true, "Must Enter Product Catagorey"],
},
reviews: [
{
name: {
type: String,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
comment: {
type: String,
required: true,
},
rating: {
type: Number,
// required: true,
},
},
{ timestamps: true },
],
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
});
module.exports = mongoose.model("Product", productSchema);
Here I want to access the values of commet for Appling filters
Here is is the output of my products
[
{
"_id": "63c4ee520ca7722674d007d5",
"product_name": "Headphones",
"product_description": "xvy",
"product_price": 8000,
"product_brand": "Apple",
"product_color": "White",
"product_stoke": 3,
"category": "Headphones",
"product_image": "public\\images\\uploaded\\products\\167385045002297820433-5f2f-43d1-972a-4b33785393ee.0ad829318c5599f429d2a6e625f8bde3.jpeg",
"product_sku": "#1",
"owner": "63c4ed720ca7722674d007ab",
"reviews": [
{
"name": "Daniyal Alam",
"user": "63c43d54cf582066929c8c46",
"comment": "Good Mobbile Phone",
"rating": 4,
"_id": "63cbce2cd52bf9ecfdf29323"
}
],
"__v": 1
},
{
"_id": "63c4e3530ca7722674d006b6",
"product_name": "Air bud Two.",
"product_description": "In the busy world which is fil.",
"product_price": 50000,
"product_brand": "Apple",
"product_color": "White",
"product_stoke": 5,
"category": "Headphones",
"product_image": "public\\images\\uploaded\\products\\167384763581197820433-5f2f-43d1-972a-4b33785393ee.0ad829318c5599f429d2a6e625f8bde3.jpeg",
"product_sku": "33",
"owner": "63c4d8ac0ca7722674d00529",
"reviews": [],
"__v": 0
},
]
I want to access my comments I tried the following code but it only returns reviews
exports.commentProduct = async (req, res, next) => {
const newproduct = await Product.find({});
try {
const reviews = newproduct?.map((p) => {
if (typeof p.reviews != "undefined") {
console.log(p.reviews);
}
});
const com = reviews?.map((c) => {
// console.log(comments);
});
// const comments = reviews.comment;
return res.status(200).json({
success: true,
reviews,
});
} catch (error) {
return res.status(500).json({
success: false,
message: error.message,
});
}
};
the Console Prints products having reviews but after applying dot notation on reviews I got undefined
[
{
name: 'Daniyal Alam',
user: new ObjectId("63c43d54cf582066929c8c46"),
comment: 'BEst One',
rating: 5,
_id: new ObjectId("63cbce44d52bf9ecfdf29743")
}
]
[]
[]
[]
[]
[]
[]
[]
[]
[
{
name: 'Daniyal Alam',
user: new ObjectId("63c43d54cf582066929c8c46"),
comment: 'pp',
rating: 4,
_id: new ObjectId("63c4f76e0ca7722674d040ae")
}
]
[]
[
{
name: 'Daniyal Alam',
user: new ObjectId("63c43d54cf582066929c8c46"),
comment: 'Good Mobbile Phone',
rating: 4,
_id: new ObjectId("63cbce2cd52bf9ecfdf29323")
}
]
Working with your example, you can map each item, then map the reviews, and get the comment out of each like using the following code
const data = [{
"_id": "63c4ee520ca7722674d007d5",
"product_name": "Headphones",
"product_description": "xvy",
"product_price": 8000,
"product_brand": "Apple",
"product_color": "White",
"product_stoke": 3,
"category": "Headphones",
"product_image": "public\\images\\uploaded\\products\\167385045002297820433-5f2f-43d1-972a-4b33785393ee.0ad829318c5599f429d2a6e625f8bde3.jpeg",
"product_sku": "#1",
"owner": "63c4ed720ca7722674d007ab",
"reviews": [{
"name": "Daniyal Alam",
"user": "63c43d54cf582066929c8c46",
"comment": "Good Mobbile Phone",
"rating": 4,
"_id": "63cbce2cd52bf9ecfdf29323"
}],
"__v": 1
}]
data.map((dat) => {
dat["reviews"].map((rev) => {
document.querySelector('div').innerHTML +=rev["comment"]
})
})
<div></div>
How can I grab the _id of sellerId inside the products? So my backend crash because I change the schema and won't compute the total sum, so right now, how can I grab it.
so this is my data.
{
"_id": "636656163b470e00d0c44872",
"userId": {
"_id": "6366559f3b470e00d0c447e9",
"studentId": "1234567890"
},
"products": [
{
"productId": {
"_id": "636655f03b470e00d0c447fb",
"title": "Shoe Cabinet",
"img": "https://firebasestorage.googleapis.com/v0/b/tua-ecom.appspot.com/o/1667651055293%5Bobject%20File%5D?alt=media&token=608c62f4-915c-47ce-a817-b025bebff06f"
},
"quantity": 1,
"sellerId": {
"_id": "636655c53b470e00d0c447eb",
"studentId": "1234567891"
},
"_id": "636656163b470e00d0c44873"
}
],
"amount": 100,
"location": "gym",
"time": "8 am",
"status": "pending",
"tax": 1,
"createdAt": "2022-11-05T12:24:54.934Z",
"updatedAt": "2022-11-05T12:24:54.934Z",
"__v": 0
},
This is request.
router.get("/total/:id", async (req, res) => {
const { id } = req.params;
try {
const income = await Order.aggregate([
{$match:
{
"products.sellerId" : {"$elemMatch": {"_id": id}}
}
},
{$project: {amount: 1}},
])
console.log("Hello")
res.status(200).json(income);
} catch (err) {
res.status(500).json({err: err.message});
}
});
note, the id inside the sellerId, is the params I'm using in the router, what I'm trying to do is grab the orders of specific users and compute it.
EDIT: ADDED SCHEMA
OrderSchema.js
const OrderSchema = new mongoose.Schema({
userId: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
products: [
{
productId:{
type: mongoose.Schema.Types.ObjectId, ref: 'Product'
},
quantity: {
type: Number,
default: 1,
},
sellerId: {
type: mongoose.Schema.Types.ObjectId, ref: 'User'
}
}
],
amount: {type: Number,required: true},
location:{type: Object, required:true},
time: {type: String, required: true},
status: {type:String, default: "pending"},
tax: {type: Number,}
}, {timestamps: true}
)
export default mongoose.model('Order', OrderSchema)
As specified below, I have section and class schema in my MongoDB.
How can I query all the students of a given list of Class IDs?
const sectionsSchema = new Schema({
section: {
type: String,
required: false
},
students:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}]
})
const classSchema = new Schema({
name:{
type: String,
required: true
},
institution: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Institution'
},
divisions :[{
type: sectionsSchema,
required: true
}]
},{timestamps: true})
Below is the Example Data
Class: [{
_id: 'Class1',
institution: 'inst1',
divisions:[{
section: 'A',
students: ['Stud1','Stud2']
},
{
section: 'B',
students: ['Stud3','Stud4']
}]
},
{
_id: 'Class2',
institution: 'inst1',
divisions:[{
section: 'A',
students: ['Stud5','Stud6']
}]
}]
input: ['Class1','Class2'];
Expected Output: ['Stud1','Stud2','Stud3','Stud4','Stud5','Stud6'];
My suggestion is to use an aggregate query as following:
.aggregate([
{
$match: {
_id: {
$in: [
"Class1",
"Class2"
]
}
}
},
{
$unwind: "$divisions"
},
{
$unwind: "$divisions.students"
},
{
"$replaceRoot": {
"newRoot": "$divisions"
}
},
])
Example output:
[
{
"section": "A",
"students": "Stud1"
},
{
"section": "A",
"students": "Stud2"
},
{
"section": "B",
"students": "Stud3"
},
{
"section": "B",
"students": "Stud4"
},
{
"section": "A",
"students": "Stud5"
},
{
"section": "A",
"students": "Stud6"
}
]
You afterwards have to map the documents returned to simple strings, since mongoose is not able to return plain strings.
for the following collection:
id: Number
name:[
new Schema({
language: { type: String, enum: ['en-US', 'fr-CA'] },
text: String,
},{ _id: false }
);
],
isActive: Boolean
and sample data like the following:
{
id:1,
"name": [
{"language": "en-US", "text": "Book"},
{"language": "fr-CA", "text": "livre"}
],
isActive:true
// and so many other fields
},
{
id:2,
"name": [
{"language": "en-US", "text": "Pen"}
],
isActive:true
// and so many other fields
}
I would like to update the document by Id:1 and change the text only for french, I tried by:
const input={ "id":"1", "isActive": false}
const name= { "name": [{"language": "fr-CA", "text": "Nouvel article"}]}
await langs.findByIdAndUpdate(
{ _id: input.id },
{ ...input, $addToSet: { name } },
{ new: true, upsert: true }
);
but the result is: (added another french item)
{
id:1,
"name": [
{"language": "en-US", "text": "Book"},
{"language": "fr-CA", "text": "livre"},
{"language": "fr-CA", "text": "Nouvel article"}
],
isActive:false
},
This is based on Brit comment:
https://mongoplayground.net/p/atlw5ZKoYiI
Please advise.
As long as that attribute already exists on the document, you can do something like:
Collection.findOneAndUpdate({id: 1}, {
$set: {
"name.$[elem]": name
}
},
{
arrayFilters: [ { "elem.language": name.language } ],
upsert: true,
new: true
})
Good Morning,
So I seem to have an issue with populating my fields with Node.js and Mongoose. It is just turning up a blank array:
Result: (JSON)
[
{
"courseassignments": [],
"_id": "5db56ceb4cc2c92824ae2651",
"name": "Garibaldi",
"website": "www.garibaldi.org.uk",
"__v": 0
},
{
"courseassignments": [],
"_id": "5db56d074cc2c92824ae2652",
"name": "Kirk Hallam",
"website": "www.kirkhallamacademy.co.uk",
"__v": 0
}
]
Below is the code I am using the call the populate function, plus the models that I am using for each of the data. It is very weird.
*school.js (Model) *
// Require modules within our file:
const mongoose = require('mongoose')
const schoolSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
trim: true
},
website: {
type: String,
required: true,
trim: true
},
logo: {
type: Buffer
},
courseassignments: [{
type: mongoose.Schema.Types.ObjectID,
ref: 'CourseAssignment'
}]
})
// Export the user to use within other files:
const school = mongoose.model('School', schoolSchema)
module.exports = school
courseassignment.js (Model)
// Require modules within our file:
const mongoose = require('mongoose')
const courseAssignmentSchema = new mongoose.Schema({
school: {
type: mongoose.Schema.Types.ObjectID,
required: true,
ref: 'School'
},
course: {
type: mongoose.Schema.Types.ObjectID,
required: true,
ref: 'Course'
}
})
// Export the user to use within other files:
const courseAssignment = mongoose.model('CourseAssignment', courseAssignmentSchema)
module.exports = courseAssignment
* Code to fetch data: (within app.js)*
router.get('/school', async (req, res) => {
const schools = await School.find({}).populate({ path: 'courseassignments' })
res.send(schools)
})
I would remove the courseassigment ref from the School model, and would take advantage of virtual populate.
So here are the steps:
school.js (school model - as you see I removed courseassignments ref, and added options for virtual features)
const mongoose = require('mongoose')
const schoolSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
trim: true
},
website: {
type: String,
required: true,
trim: true
},
logo: {
type: Buffer
}
}, {
toJSON: { virtuals: true },
toObject: { virtuals: true }
})
schoolSchema.virtual("courseassignments", {
ref: "CourseAssignment",
foreignField: "school",
localField: "_id"
})
const school = mongoose.model('School', schoolSchema)
module.exports = school
At this point when you hit the schools endpoint, your response will be like this.
( I only show one item to be short.)
[
{
"_id": "5db5a809cfc9951770d5078a",
"name": "school 1",
"website": "school 1 website",
"__v": 0,
"courseassignments": [
{
"_id": "5db5a892cfc9951770d50790",
"school": "5db5a809cfc9951770d5078a",
"course": "5db5a847cfc9951770d5078d",
"__v": 0
},
{
"_id": "5db5a89ccfc9951770d50791",
"school": "5db5a809cfc9951770d5078a",
"course": "5db5a851cfc9951770d5078e",
"__v": 0
},
{
"_id": "5db5a8a1cfc9951770d50792",
"school": "5db5a809cfc9951770d5078a",
"course": "5db5a858cfc9951770d5078f",
"__v": 0
}
],
"id": "5db5a809cfc9951770d5078a"
},
...
...
]
And if you also want to access to the Course name (which I think would be good),
courseassigment.js
const mongoose = require('mongoose')
const courseAssignmentSchema = new mongoose.Schema({
school: {
type: mongoose.Schema.Types.ObjectID,
required: true,
ref: 'School'
},
course: {
type: mongoose.Schema.Types.ObjectID,
required: true,
ref: 'Course'
}
}, {
toJSON: { virtuals: true },
toObject: { virtuals: true }
})
courseAssignmentSchema.pre(/^find/, function (next) {
this.populate({
path: 'course'
});
next();
});
// an index may be required like this
//courseAssignmentSchema.index({ school: 1, course: 1 }, { unique: true });
const courseAssignment = mongoose.model('CourseAssignment', courseAssignmentSchema)
module.exports = courseAssignment
And with this the result will contain the course related fields like course name.
[[
{
"_id": "5db5a809cfc9951770d5078a",
"name": "school 1",
"website": "school 1 website",
"__v": 0,
"courseassignments": [
{
"_id": "5db5a892cfc9951770d50790",
"school": "5db5a809cfc9951770d5078a",
"course": {
"_id": "5db5a847cfc9951770d5078d",
"name": "course 1",
"__v": 0
},
"__v": 0,
"id": "5db5a892cfc9951770d50790"
},
{
"_id": "5db5a89ccfc9951770d50791",
"school": "5db5a809cfc9951770d5078a",
"course": {
"_id": "5db5a851cfc9951770d5078e",
"name": "course 2",
"__v": 0
},
"__v": 0,
"id": "5db5a89ccfc9951770d50791"
},
{
"_id": "5db5a8a1cfc9951770d50792",
"school": "5db5a809cfc9951770d5078a",
"course": {
"_id": "5db5a858cfc9951770d5078f",
"name": "course 3",
"__v": 0
},
"__v": 0,
"id": "5db5a8a1cfc9951770d50792"
}
],
"id": "5db5a809cfc9951770d5078a"
},
...
...
]
Docs:
https://mongoosejs.com/docs/tutorials/virtuals.html
https://mongoosejs.com/docs/populate.html#populate-virtuals