Trouble using mongoose 'Populate' - javascript

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

Related

How to access nested elements of json object in node js and mongodb

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 inside a nested array/objects?

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)

How to create an array entry with ObjectId and Number

I am new to mongodb and am trying to make this type of entry:
{
"resources": [
{
"amount": 1,
"resource": {
"_id": "61be82b9549b4ede0c8df07e"
}
}
]
}
Here is my schema code:
const schema = new Schema({
resources: [
{
amount: {
type: Number,
required: true,
},
resource: {
_id: {
type: Schema.Types.ObjectId,
ref: "Resource"
}
}
}
]
});
here is the json code i send
{
"resources": [
{
"amount": 1,
"resource": {
"_id": "61be82b9549b4ede0c8df07e"
}
}
]
}
After processing the request, the following entry is created
{
"resources": [
{
"amount": 1,
"resource": {
"_id": "61be82b9549b4ede0c8df07e"
},
"_id": "61ebf5d2e47442bd566fe157"
}
],
"_id": "61ebf5d2e47442bd566fe156",
"__v": 0
}
Id for the resource was created correctly, but I can't figure out where the resources._id key came from? Where did I make a mistake?
You have to off _id from schema declaration in the array, after updating schema try inserting new document,
const schema = new Schema({
resources: [
{
_id: false,
amount: {
type: Number,
required: true,
},
resource: {
_id: {
type: Schema.Types.ObjectId,
ref: "Resource"
}
}
}
]
});

Mongodb : Adding new data object into an array of object with node.js mongoose [duplicate]

This question already has answers here:
Mongodb $push in nested array
(4 answers)
Closed 1 year ago.
I want to add a new data object inside of a nested document in MongoDB. this is what my schema look like :
const transactionSchema = new Schema({
transactionType: {type: String, require: true, trim: true},
senderWallet: {type: String, require: true, trim: true},
recipientWallet: {type: String, require: true, trim: true},
amount: {type: Number, require: true, trim: true},
createdAt: {type: Date, require: true},
});
const walletHoldShema = new Schema({
balance: {type: Number},
transaction:[transactionSchema]
});
const walletSchema = new Schema({
createdAt: {type: Date, require: true},
userId: {type: String, require: true, trim: true},
walletAdrress: {type: String},
usdWallet: [walletHoldShema],
})
const Wallets = mongoose.model('wallet', walletSchema);
module.exports = Wallets
This is what my data look like right now
wallet: {
"_id": "60ca5e8e2c57463733b65f89",
"usdWallet": [
{
"_id": "60ca5ede2c57463733b65f8a",
"balance": 0,
"transaction": []
}
],
"createdAt": "2021-06-16T20:28:14.589Z",
"userId": "fb0df5c9a9eb",
"walletAdrress": "fb0df5c9a9eb",
"__v": 0
}
I have tried different solution like this one which I followed via stack :
const _id = req.params._id;
const transactionInput = {
transactionType: 'input',
senderWallet: req.body.sender,
recipientWallet: req.body.recipient,
amount: req.body.amount,
createdAt: Date.now(),
};
walletSchema.findOneAndUpdate({_id: _id}, {$push: {transaction: transactionInput}}, { new: true }, function(err, data){
if (err) {
res.send(err);
} else {
res.send(transactionInput);
}
});
// calling router
router.patch('/v1/sendUSD/', wallet.sendDollar
But I am getting this in my DB after my router is called :
"wallet": [
{
"_id": "60ca5e8e2c57463733b65f89",
"usdWallet": [
{
"_id": "60ca5ede2c57463733b65f8a",
"balance": 0,
"transaction": []
}
],
"createdAt": "2021-06-16T20:28:14.589Z",
"userId": "fb0df5c9a9eb",
"walletAdrress": "fb0df5c9a9eb",
"__v": 0
},
{
"_id": "60ca5e8e2c5746373",
"usdWallet": [
{
"_id": "60ca5ede2c57463733b65f8a",
"transaction":
[
{
"transactionType": "input",
"senderWallet": "fcdhjgknsdfihber",
"recipientWallet": "mbindu",
"amount": "50.0",
"createdAt": 1623881009306
}
]
}
],
},
]
But what I want is this :
wallet: [
{
"_id": "60ca5e8e2c57463733b65f89",
"usdWallet": [
{
"_id": "60ca5ede2c57463733b65f8a",
"balance": 0,
"transaction":
[
{
"transactionType": "in",
"senderWallet": "fcdhjgknsdfihber",
"recipientWallet": "mbindu",
"amount": "50.0",
"createdAt": 1623881009306
},
{
"transactionType": "out",
"senderWallet": "fcdhjgknsdfihber",
"recipientWallet": "mbindu",
"amount": "50.0",
"createdAt": 1623881009306
},
]
}
],
"createdAt": "2021-06-16T20:28:14.589Z",
"userId": "fb0df5c9a9eb",
"walletAdrress": "fb0df5c9a9eb",
"__v": 0
},
]
having an array inside an array is always a bad idea. that said, you can push transaction into usdWallet through:
walletSchema.findOneAndUpdate({ _id: _id }, { $push: { "usdWallet.$.transaction": transactionInput }}, { new: true }, function(err, data) {
if (err) {
res.send(err);
} else {
res.send(transactionInput);
}
});

Getting foreign key undefine in Console.log and in api response

I have table report_data which is belongs to daily_entry table but when I call api like to get all data of daily_entry table it send response like below
output
{
"response_code": "0",
"message": "Operation is successfully executed",
"status": "success",
"data": {
"id": 1,
"user_id": 1,
"date": "12-10-2020",
other data ....
"is_active": true,
"createdAt": "2020-10-21T06:25:57.877Z",
"updatedAt": "2020-10-21T06:25:57.877Z",
"report_datum": {
"id": 1,
"entry_i": 1, <<<<<<<----------OUTPUT
"Date": null,
"report_document_id": "2",
"createdAt": "2020-10-21T06:26:02.642Z",
"updatedAt": "2020-10-21T06:26:02.642Z"
}
},
"level": "info",
"timestamp": "2020-10-21T06:25:45.947Z"
}
expected
{
"response_code": "0",
"message": "Operation is successfully executed",
"status": "success",
"data": {
"id": 1,
"user_id": 1,
"date": "12-10-2020",
other data ....
"is_active": true,
"createdAt": "2020-10-21T06:25:57.877Z",
"updatedAt": "2020-10-21T06:25:57.877Z",
"report_data": {
"id": 1,
"entry_id": 1,<<<<<-------------EXPECTED
"Date": null,
"report_document_id": "2",
"createdAt": "2020-10-21T06:26:02.642Z",
"updatedAt": "2020-10-21T06:26:02.642Z"
}
},
"level": "info",
"timestamp": "2020-10-21T06:25:45.947Z"
}
relation between both table is hasOne
db.daily_entry.hasOne(db.report_data, { onDelete: "cascade", foreignKey: 'entry_id', foreignKeyConstraint: true, targetKey: 'id' });
I have logged data coming from db it was like below
dataValues:{id: 1, entry_i: 1, daily_entry : 8468476, date: 23-10-2020, …}
get entry_id:ƒ () {\n return this.get(attribute);\n }
undefined
I have checked in my whole project there is no name like entry_i
API I code is below
getdaily_entryById: async (req, res) => {
sequelize.sequelize.transaction(async (t1) => {
if (!req.params.id) {
logger.warn(error.MANDATORY_FIELDS)
return res.status(500).send(error.MANDATORY_FIELDS);
}
let data = await sequelize.daily_entry.findOne({
where: { id: req.params.id },
include: [
sequelize.report_data
]
});
let result = error.OK
result.data = data
logger.info(result);
return res.status(200).send(result);
}).catch(function (err) {
logger.warn(err)
console.log(err)
return res.status(500).send(error.SERVER_ERROR);
});
}
daily_entry table schema
module.exports = function (sequelize, DataTypes) {
const daily_entry = sequelize.define('daily_entry ', {
user_id: {
type: DataTypes.INTEGER(),
allowNull: true
},
date: {
type: DataTypes.STRING,
allowNull: true
},
report_status: {
type: DataTypes.STRING,
allowNull: true
},
high_close: {
type: DataTypes.DOUBLE(),
allowNull: true
},
high_open: {
type: DataTypes.DOUBLE(),
allowNull: true
},
low_close: {
type: DataTypes.DOUBLE(),
allowNull: true
},
low_open: {
type: DataTypes.DOUBLE(),
allowNull: true
},
is_active: {
type: DataTypes.BOOLEAN,
allowNull: true
}
});
return daily_entry
};
report_data tables schema
module.exports = function (sequelize, DataTypes) {
const report_data= sequelize.define('report_data', {
daily_entry : {
type: DataTypes.INTEGER(),
allowNull: true
},
Date: {
type: DataTypes.INTEGER(),
allowNull: true
},
report_document_id: {
type: DataTypes.TEXT,
allowNull: true
}
},
{
tableName: 'report_data'
});
return report_data
};
So, Where am I doing wrong and why I am getting entry_i as foreign key
Try To change your table name to CamelCase and then try.
I know this should be comment but at this time I don't have privilege of comment

Categories