Casting error while saving in the database - node.js

I am using Angular as frontend and NodeJS for the backend.
I have a route that saves the data received from the frontend to the database. When I execute the save() method, I get prompted the following error:
err : ValidationError: conf.0: Cast to [Boolean] failed for value "[ {
name: 'v', percentage: 2, type: false, status: true } ]" (type string)
at path "conf.0"
Below is the route that stores the data:
app.post("/api/submitTaxCollection", (req, res) => {
console.log(req.body);
const submitTaxSchema = new addTaxesSchema(req.body);
try {
submitTaxSchema.save(function (err) {
if (err) return console.log("err : " + err);
});
} catch (error) {
console.log("ERROR : " + error);
return res.send(error);
}
});
and this is the schema.ts file:
var mongoose = require("mongoose");
//Define a schema
var taxSchema = mongoose.Schema;
var AddTaxSchema = new taxSchema({
parentId: String,
conf: [
{
name: String,
percentage: Number,
type: Boolean,
status: Boolean,
},
],
});
var newTaxesSchema = mongoose.model("addTaxSchema", AddTaxSchema);
module.exports = newTaxesSchema;
In Angular, model is setup as below:
export class TaxRatesConfigurationsModel {
name: string = "";
percentage: number = 0;
type: boolean = false;
status: boolean = true;
}
export class TaxRatesModel {
parentId: string = "";
conf: TaxRatesConfigurationsModel[] = [];
}
and I am calling the API as below:
this._httpService
.post(environment.url + "/api/submitTaxCollection", request)
.subscribe((data) => {
console.log(data);
});
when I console.log(req.body);, I get the following printed to the console (Nodejs):
{
parentId: '23948923nur8cw9yicnyu',
conf: [ { name: 'v', percentage: 2, type: false, status: true } ]
}
and the error occurs in Nodejs
What is causing this weird issue?

Related

Ajv and Ajv-errors

I am using the ajv errors plugin for fastify to throw schema errors for required properties however every error is prefixed with 'body' then my error message. Is there any way to remove the schema prefix from errors?
example:
body: {
type: 'object',
properties: {
title: {
type: 'string',
description: "The title of the thing",
},
required: ['title'],
errorMessage: {
required: {
title: 'BEEP BOOP TITLE NEEDED!',
},
},
},
my fastify config:
const app = fastify({
ajv: {
customOptions: {
allErrors: true,
},
plugins: [(ajv) => AjvErrors(ajv, { singleError: false, keepErrors: false })],
},
});
Expected error for missing title in a request: 'BEEP BOOP TITLE NEEDED!'
Actual: 'body BEEP BOOP TITLE NEEDED!''
fastify: "4.1.0"
ajv-errors: "3.0.0"
What you can do is a simple trick with fastify ;)
fastify.setErrorHandler(function (error, request, reply) {
// Log error
this.log.error(error);
const err = error;
if (error?.validation?.length) {
err.message = error.validation[0].message;
}
// Send error response
return reply.status(error.statusCode || 400).send(err);
});
There is the schemaErrorFormatter option
const fastify = Fastify({
schemaErrorFormatter: (errors, dataVar) => {
// errors = ajv errors
// dataVar = `body` string
return new Error(myErrorMessage)
}
})

How to update existing MongoDB document with Nested JSON using Angular?

I am trying to store JSON array to the existing document with the id who logged in. I don't have an idea how to post this array to backend.
cake.component.ts
export class CakeComponent implements OnInit {
form: FormGroup;
constructor(
public fb: FormBuilder,
private api: ApiService
) { }
ngOnInit() {
this.submitForm();
}
submitForm() {
this.form = this.fb.group({
url: ['', [Validators.required]],
width : ['', [Validators.required]],
height: ['', [Validators.required]]
})
}
submitForm() {
if (this.form.valid) {
this.api.AddCake(this.form.value).subscribe();
}
}
}
Existing MongoDB document Cakes
{
"id": "0001",
"type": "donut",
"name": "Cake"
}
Expected Output
{
"id": "0001",
"type": "donut",
"name": "Cake",
"image": {
"url": "images/0001.jpg",
"width": 200,
"height": 200
}
}
Here is the basic code, please update it accordingly :
/** You can split this code into multiple files, schema into a file &
mongoDB connectivity into a common file & actual DB update can be placed where ever you want */
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const cakeSchema = new Schema({
id: String,
type: String,
name: String,
image: {
url: String,
width: Number,
height: Number
}
});
const cakeModel = mongoose.model('Cakes', cakeSchema, 'Cakes');
let form = {
"url": "images/0001.jpg",
"width": 200,
"height": 200
}
async function myDbConnection() {
const url = 'yourDBConnectionString';
try {
await mongoose.connect(url, { useNewUrlParser: true });
console.log('Connected Successfully')
let db = mongoose.connection;
// You can use .update() or .updateOne() or .findOneAndUpdate()
let resp = await cakeModel.findOneAndUpdate({ id: '0001' }, { image: form }, { new: true });
console.log('successfully updated ::', resp)
db.close();
} catch (error) {
console.log('Error in DB Op ::', error);
db.close();
}
}
module.exports = myDbConnection();
Update :
In case if you're using mongoDB driver but not mongoose :
const MongoClient = require('mongodb').MongoClient;
// Connection URL
const url = 'yourDBConnectionString';
// Database Name
const dbName = 'test';
// Create a new MongoClient
const client = new MongoClient(url);
let form = {
"url": "images/0001.jpg",
"width": 200,
"height": 200
}
// Use connect method to connect to the Server
client.connect(async function (err) {
if (err) console.log('DB connection error ::', err)
console.log("Connected successfully to server");
try {
// You can use .update() or .updateOne() or .findOneAndUpdate()
let resp = await client.db(dbName).collection('Cakes').findOneAndUpdate({ id: '0001' }, { $set: { image: form } }, { returnOriginal: false });
console.log('successfully updated ::', resp , 'resp value ::', resp.value)
client.close();
} catch (error) {
console.log('Error in DB Op ::', error);
client.close();
}
});

Schema validate causes Save to fail in Mongoose

Why does the following code causes the Mongoose save to fail? If I remove validate: utils.uuid.isValid (returns a boolean) the process will complete:
var accountSchema = new mongoose.Schema({
_id : { type: String, default: utils.uuid.init, validate: utils.uuid.isValid },
n : { type: String }, // Display Name
ac : { type: Date },
au : { type: Date },
ad : { type: Date },
am : { type: String }
});
Also, if I remove the validate property of the field, and try setting values in the pre('validate', cb) or pre('save', cb) call, this will cause the same result:
accountSchema.pre('validate', function(next) {
var now = new Date(),
memberId = this.am;
console.log('In Account validate (member : ' + memberId + ')');
if (this.isNew) { this.ac = now; console.log('Item is new.'); }
else if (this.isModified()) { this.au = now; console.log('Item is modified.'); }
else { return next();
console.log('Canceling Account validate.');
}
console.log(JSON.stringify(this));
console.log('Completed Account validate.');
next();
});
Nothing crashes. In Webstorm, processing just stops with a message "Process finished with exit code 139".

MongoDB : Nested array update issue

I am using MEAN stack to display the following array in a grid.
Nested array:
{
"_id":"1",
"appDomain":[
{
"appDomainName":"XYZ",
"dashboard":[
{
"envName":"UAT",
"envDetails":[
{
"hostnme":"ABC",
"ip":"sdsdsdsd",
"cpu":"-------",
"memory":"-------",
"disk":"-------",
"downtime":"sdsdsdsd",
"version":"dsdsdsd",
"hostDetails":[
{
"hostHdrName":"tomcat",
"hostDetails":[
{
"hostname":"FLT",
"status":"UP",
"path":"dfdf",
"host":"sdsdsd",
"port":"1112"
}
]
}
]
}
]
}
]
},
{
"appDomainName":"ABC",
"dashboard":[
{
"envName":"UAT",
"envDetails":[
{
"hostnme":"ABC",
"ip":"sdsdsdsd",
"cpu":"-------",
"memory":"-------",
"disk":"-------",
"downtime":"sdsdsdsd",
"version":"dsdsdsd",
"hostDetails":[
{
"hostHdrName":"tomcat",
"hostDetails":[
{
"hostname":"FLT",
"status":"UP",
"path":"dfdf",
"host":"dfdfdf",
"port":"1112"
},
{
"hostname":"SHP",
"status":"DOWN",
"path":"dfdfdf",
"host":"fgfgfg",
"port":"1112"
}
]
}
]
}
]
}
]
}
]
}
Mangoose update: I am using express.js to add/update and delete the entry in MangoDB. I am facing the issue in update in nested array. Please see below the code for update the nested array.
router.post('/appDomain/update/:appDomainName/:envName', function(req, res, next) {
AppDomain.findOne({}, {_id: 0, appDomain: {$elemMatch: {appDomainName: req.params.appDomainName,}}}, function (err, appDomain) {
if(appDomain.appDomain[0].dashboard[0].envName == req.params.envName )
appDomain.appDomain[0].dashboard[0].envDetails.push({})
appDomain.save(function (err) {
if(err) {
console.error('ERROR!');
}
});
res.json(appDomain);
});
})
However, it is not updating. It would be great if anyone can help me out..
AppDomainModel Schema
var Schema = mongoose.Schema;
var serverDetails = new Schema({
hostname: String,
ip: String,
status: String,
path: String,
host: String,
port: String
});
var hostDetail = new Schema({
hostHdrName: String,
hostDetails: [serverDetails]
});
var keyValue = new Schema({
keyHdrName: String,
keyValueData: [{key: String, value:String}]
});
var envSchema = new Schema({
hostnme: String,
ip: String,
cpu: String,
memory: String,
disk: String,
downtime: String,
version: String,
hostDetails: [hostDetail],
keyValues: [keyValue],
activities:{
recent: [keyValue],
planned: [keyValue]
}
});
var dashboardSchema = new Schema({
envName: String,
envDetails: [envSchema]
});
var appDomainSchema = new Schema({
_id:String,
appDomain:[{
appDomainName: {type:String,index: { unique: true }},
dashboard: [dashboardSchema]
}]
});
var AppDomain = mongoose.model('AppDomain', appDomainSchema);
var Dashboard = mongoose.model('Dashboard', dashboardSchema);
var EnvSchema = mongoose.model('EnvSchema', envSchema);
After updating.I am using the following function to check the value .. However the updated one is not available in the DB.
router.get('/app/domain/get/:appDomainName', function(req, res, next) {
AppDomain.find({}, {_id: 0, appDomain: {$elemMatch: {appDomainName: req.params.appDomainName,}}},function (err, appDomain) {
res.json(appDomain);
});
});
After a long struggle, I figured it out . See below the answer.
var data2 = {};
AppDomain.update(
{_id:1,'appDomain.appDomainName': req.params.appDomainName,'dashboard.$.envName':{$nin:[req.params.envName]}},
{$push: {'appDomain.$.dashboard.0.envDetails':{'envDetails':[data2]}}},
function(err, model) {
console.log(err);
}
);
I suspect your changes are actually being saved successfully, but you're returning the response too soon. Try this:
appDomain.save(function (err, savedAppDomain) {
if(err) {
console.error('ERROR!');
next(err);
return;
}
res.json(savedAppDomain):
});
// Removed:
//res.json(appDomain);
//});

MongoDB: stored base64 buffer data and retrieved base64 does not match

I am posting small sized base64 encoded images (around 100-200K each) directly into mongodb using Mongoose. Before storing I could see the content is same as what sent from the client. But the query base64 string is not same as what went in? Any idea what I am missing ?
// process the add image request
app.post('/addimage', function(req, res) {
console.log("Addimage post....");
var qry = {'_email' : req.user.local.email, 'date' : req.body.date, 'subject' : req.body.subject };
Item.findOne(qry, function(err, item) {
if (err) {
console.log('Find images failed: ' + err);
var resp = '{"result" : "failed", "msg" : ' + err + ', "_req" : "addimage"}';
res.send(resp);
} else {
if (item == null) { // item doesn't exist, create now
var item = new Item();
item._email = req.body._email;
item.date = req.body.date;
item.subject = req.body.subject;
}
// add image
var image = new Image();
image.timestamp = req.body.timestamp;
image.contentType = req.body.contentType;
var imgBuf = new Buffer(req.body.image, 'base64');
image.image = imgBuf;
item.images.push(image);
item.save(function(err, result) {
if (err) {
console.log('Find images failed: ' + err);
var resp = '{"result" : "failed", "msg" : ' + err + ', "_req" : "addimage"}';
res.send(resp);
} else {
res.send('{"result" : "ok", _req: "addimage"}');
console.log("Image saved and responded to ...");
}
});
}
});
});
The data string stored in req.body.image started with something like "/9j/4AAQSkZJ ..." but from mongo shell I see it different. Is it the subtype 0 for the Bindata that's causing this ?
> db.items.find({subject:"Science"},{'images.image':1})
{ "_id" : ObjectId("547382943fc884447a767d58"), "images" : [ { "image" : BinData(0,"LwA5AGoALwA0AEEAQQBRAFMAawBaAEoAUgBnAEEAQgBBAFEAQQBBAEEAUQBBAEIAQQBBAEQALwA0AFEAQgBZAFIAWABoAHAAWgBnAEEAQQBUAFUAMABBAEsAZwBBAEEAQQBBAGcAQQBBAGcARQBTAEEAQQBN
Schema:
var imageSchema = new mongoose.Schema({
timestamp : String,
contentType : String,
image : Buffer,
}, { strict: true });
imageSchema.index({ timestamp: 1}, { unique: true });
var itemSchema = new mongoose.Schema({
_email : {
type: String,
required: true,
},
date : {
type: String,
required: true,
},
subject : {
type: String,
required: true,
},
images : [imageSchema],
}, { strict: false });
itemSchema.index({ _email: 1, date: 1, subject: 1}, { unique: true });
Mongodb version 2.6.5, Mongoose 3.8.1, Node v0.11.6-pre
Also, tried 'utf8' / 'ascii' / 'ucs2' instead of 'base64' while creating Buffer object.
Thanks!
It was node version ;( Restoring to 0.10.33 solved the issue !

Resources