MongoDB - NodeJs - Maximum call stack size exceeded - node.js

I get this error when saving the schema below in MongoDB/NodeJs (with Mongoose):
Uncaught RangeError: Maximum call stack size exceeded.
This occurs when I add details in my schema in the Array:
var mongoose = require('mongoose');
const Attribute = new mongoose.Schema({
context: String,
format: String,
measurand: String,
location: String,
unit: String
});
const Value = new mongoose.Schema({
value: Number,
attributes: Attribute
});
module.exports = mongoose.model('MeterValue',{
chargeBoxID: {type: String, ref: 'ChargingStation'},
connectorId: Number,
transactionId: Number,
timestamp: Date,
values: [Value]
});
Any idea?
Thanks in advance!
Serge.

I think you have to define an extra schema for the model in the array.
Something like:
const AddressSchema mongoose.Schema({
address1: { type: String },
address2: { type: String },
});
...
module.exports = mongoose.model('Person',{
_id: String,
name: String,
address: [ AddressSchema ],
});

Related

Mongoose is Casting a String Value to an ObjectId and is Crashing my App

I have a simple form that posts to a route, and I'm trying to take the object from that form data and create a new document in my mongoDB using mongoose.
The controller for this functionality looks like:
module.exports.newItem = async (req, res) => {
const formData = req.body.item;
const curbsideItem = new CurbsideItem(formData);
console.log(curbsideItem);
await curbsideItem.save();
res.redirect(`/items/${curbsideItem._id}`);
}
And the console.log(curbsideItem) looks like:
{"name":"Test","location":{"addressLineOne":"test","addressLineTwo":"","city":"Test","state":"PA","zip":15000},"category":"furniture","details":"Random Details Here","image":"No Img","_id":"630a6b2eb7a51d9b2e17e2ef","__v":0}
but for some reason, I think the image string value is trying to be casted into an ObjectId as I'm getting the following error that crashes my app:
const castError = new CastError();
^
CastError: Cast to ObjectId failed for value "No Img" (type string) at path "_id" for model "CurbsideItem"
...
messageFormat: undefined,
stringValue: '"No Img"',
kind: 'ObjectId',
value: 'No Img',
path: '_id',
reason: BSONTypeError: Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer
I don't understand why this is occuring, I've been stuck on this for two hours now and googleing hasn't helped. My schema looks fine, I'm really not sure what to do here.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const curbsideItemSchema = new Schema({
name: {
type: String,
required: true
},
location: {
addressLineOne: {
type: String,
required: true,
},
addressLineTwo: {
type: String
},
city: {
type: String,
required: true
},
state: {
type: String,
required: true
},
zip: {
type: Number,
required: true
}
},
category: {
type: String,
enum: ['furniture', 'clothing', 'toys', 'entertainment', 'other'],
required: true
},
details: {
type: String,
required: true,
maxLength: 500
},
image: {
type: String,
required: true
}
});
module.exports = mongoose.model('CurbsideItem', curbsideItemSchema);
Any help or a pointer in the right direction would be massively appreciated!

How to create a dynamic nested mongoose document with the same schema on multiple levels

Before everyone tells me I can't call a const before initializing, I do know that.
But I think this is the simplest way to render the concept I have in mind, (where any subdocument within the replies array also has the same schema as the parent, and documents within the replies array of those subdocuments also having the same schema). I would really appreciate anyone's input.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
var commentSchema = new mongoose.Schema({
content: String,
createdAt: {
type: Date,
default: Date.now
},
score: {
type: Number,
default: 1
},
username: {
type: String,
lowercase: true
},
parent: {
type: Schema.Types.ObjectId,
ref: 'comment'
},
replyingTo: String,
replies: [commentSchema]
});
module.exports = mongoose.model("comment", commentSchema);
Since a const can't be called before initialization, to fix this issue the parent schema should be called on the children array after initialization the code below:
commentSchema.add({ replies: [commentSchema] })
The final result should look like this:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const commentSchema = new mongoose.Schema({
content: String,
createdAt: {
type: Date,
default: Date.now
},
score: {
type: Number,
default: 1
},
username: {
type: String,
lowercase: true
},
parent: {
type: Schema.Types.ObjectId,
ref: 'comment'
},
replyingTo: String,
});
commentSchema.add({ replies: [commentSchema] })

How to set "capped" after collection is created?

I am attempting to set a capped parameter to my collection within my mongoose.Schema that did not include capped at first.
Any help welcome.
My Schema:
const mongoose = require('mongoose')
var Schema = mongoose.Schema;
var userSchema = new Schema({
name: { type: String, required: true },
email: { type: String },
password: { type: String },
isAdmin: {type: Boolean, default: false},
avatar: { type: String },
joinDate: { type: Date, default: Date.now() },
},{ autoCreate: true, capped : 1024})
userSchema.set('timestamps', true);
const Users = mongoose.model('Users', userSchema)
module.exports = Users;
I get following error:
Error: A non-capped collection exists with the name: users
To use this collection as a capped collection, please first convert it.
Seems like you have already created a users collection in your database. So to convert it into a capped run below command either in mongoshell or robomongo
db.runCommand( { convertToCapped: 'users', size: 1024 } )

getting a CastError, ObjectId failed for value

I have a route that is inserting an array of documents into a collection. I also want to capture the _is of the document into a user schema but I'm getting a CastError, how do I resolve this. here is my code:
the error:
(node:23088) UnhandledPromiseRejectionWarning: CastError: Cast to ObjectId failed for value "
{
_id: 6032c1df6761405a308736f0,
name: ' test1',
surname: 'test',
email: 'example#example.com',
phone: '0915461',
__v: 0
},
{
_id: 6032c1df6761405a308736f1,
name: 'jane',
surname: 'doe',
email: 'jane#gmail.com',
phone: '12345678',
__v: 0
}
]" at path "references"
route:
app.post('/register_two/:id/references', async (req, res) => {
const staff = await Worker.findById(req.params.id);
const reference = await Reference.insertMany(req.body.references);
await staff.references.push(reference); <<--- Error when i try to push document IDs
});
my reference schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ReferenceSchema = Schema({
name: String,
surname: String,
email: String,
phone: String
});
module.exports = mongoose.model('Reference', ReferenceSchema);
my worker schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const WorkerSchema = new Schema({
name: String,
surname: String,
role: String,
nationality: String,
gender: String,
dateofbirth: Date,
contactnumber: String,
email: String,
address: String,
region: String,
righttowork: String,
righttoworkproof: String,
ninumber: String,
references: [
{
type: Schema.Types.ObjectId,
ref: 'Reference'
}
],
date: Date
});
module.exports = mongoose.model('Worker', WorkerSchema);
edit: fixed worker schema
I managed to solve it using the spread operator, all I did was change:
await staff.references.push(reference);
to
await staff.references.push(...reference);
You should run the insertMany command with the rawResult option set to true
const reference = await Reference.insertMany(req.body.references, {rawResult: true});
This way you will get the raw result from the MongoDB driver back into reference. That result will be an object that will contain this prop:
...
...
insertedIds: { '0': 6032ce0ed7fd8568aef0d0cd, '1': 6032ce0ed7fd8568aef0d0ce, ... }
...
insertedIds is what you need, but you need them in the form of an array. So here is what your code should look like:
const reference = await Reference.insertMany(req.body.references, {rawResult: true});
await staff.references.push(...Object.values(reference.insertedIds));
Credit to Emil C., who pointed out that by pushing an array we would simply be creating array of arrays inside the reference path. Spreading is the answer.

How to access nested data which is a reference data in an array in mongoose?

So I have this nested data object which is also a reference data. When I try to access it using populate it is showing only the id. I do not want only the id. I also want the details to come along. Can someone please help me on this?
This is the EmployeesDetailsSchema which have this employeesinfo property with a reference in it. Now the designation and speciality property as you can see in the image is coming only in ids and not the full details i want the full the details of these two as well as the other fields also.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const EmployeesDetailsSchema = new Schema({
employeesinfo: {
type: mongoose.Schema.Types.ObjectId,
ref: "employees"
},
workingdays: Number,
fathersname: String,
pan: String,
joiningdate: Date,
gender: String,
pfno: String,
esino: String,
branchname: String,
department: String,
paymode: String,
bankname: String,
acno: String,
ifscno: String,
//Earnings
basicsalary: Number,
extra: Number,
totalE: Number,
//Days
fixeddays: Number,
presentdays: Number,
absentdays: Number,
leavedays: Number,
holidays: Number,
//Deductions
pf: Number,
esi: Number,
professionaltax: Number,
advance: Number,
absentdeductions: Number,
leavedeductions: Number,
totalD: Number,
//Net pay Details
netpay: Number,
inwords: String,
name: String,
date: {
type: Date,
default: Date.now
}
});
module.exports = EmpDetails = mongoose.model(
"empdetails",
EmployeesDetailsSchema
);
This is the EmployeesSchema which is reference in the employeesinfo property of the EmployeesDetailsSchema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const EmployeesSchema = new Schema({
name: { type: String },
email: { type: String },
speciality: {
type: mongoose.Schema.Types.ObjectId,
ref: "speciality"
},
contactno: { type: Number },
designation: {
type: mongoose.Schema.Types.ObjectId,
ref: "designation"
},
alternatecontactno: { type: Number },
address: { type: String },
employeeImage: { type: String },
imageName: { type: String },
date: { type: Date, default: Date.now() }
});
module.exports = Employees = mongoose.model("employees", EmployeesSchema);
And these are the two models which is being reference in the EmployeesSchema
//Speciality Type Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const SpecialitySchema = new Schema({
speciality: {
type: String
},
description: {
type: String
}
});
module.exports = Speciality = mongoose.model("speciality", SpecialitySchema);
//Designation Type Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const DesignationSchema = new Schema({
designation: {
type: String
},
description: {
type: String
}
});
module.exports = Designation = mongoose.model("designation", DesignationSchema);
And this is the get route
router.get("/", (req, res) => {
EmpDet.find()
.populate({
path: "employeesinfo"
})
.then(empdet => res.json(empdet))
.catch(err =>
res.status(400).json({ msg: "Error in finding Employees Details" })
);
});
Populate usually returns the entire referred document if there is no specific options set. It can be used like this:
const story = await Story.findOne({ title: 'Some Titel' }).populate('authors');
See full documentation and further samples:
https://mongoosejs.com/docs/populate.html
Try this:
EmpDet.find()
.populate({
path: "employeesinfo",
populate: [
{ path: 'speciality' },
{ path: 'designation' }
]
})
.then(empdet => res.json(empdet))
.catch(err =>
res.status(400).json({ msg: "Error in finding Employees Details" })
);
Also, please have a look at the documentation too as mentioned by Simon.
https://mongoosejs.com/docs/populate.html

Resources