i want to create a document with array field in mongodb - node.js

In mongodb schema i just want to add an array in this schema but have some problem when I insert data , all time return an error string "This library (validator.js) validates strings only"
In Model:
let prescriptionSchema = new Schema({
appointment_id: {
required: [true, 'Appointment id is required'],
type :Schema.Types.ObjectId,
ref: 'Appointments'
},
remarks: {
type: String,
},
diagnosis_description:{ type : Array , "default" : [] },
diagnosis: [{
diagnosis_description: {
type: String,
},
}],
investigation: [{
test_name: {
type: String,
},
test_description: {
type: String,
},
}],
medicine: [{
medicine_name: {
type: String,
},
medicine_dosage: {
type: String,
},
medicine_power: {
type: String,
},
}]
},
{timestamps: {
createdAt: 'created_at',
updatedAt: 'updated_at'
}});
In controller i just write a console log , so i thing problem is in mongodb , mongo can't understand then array, please help.....
In postman :
{
"appointment_id": "5d3ab1a4590ad324b2abdb76",
"remarks" : "Next checkup after one month",
"diagnosis":[
{
"diagnosis_description": "Fiver"
}
],
"investigation":[
{
"test_name" : "Blood",
"test_description" : "Dengu"
},
{
"test_name" : "Blood",
"test_description" : "HIV"
}
],
"medicine":[
{
"medicine_name":"Paracetamol",
"medicine_dosage":"650",
"medicine_power":"AM"
}
]
}
const path = require('path'),
router = require('express').Router(),
dir = ${path.dirname(__dirname)}/controllers,
helperLib = require(path.resolve('./config/lib/helper_lib'));
This is routes :
let ReadDirectory = new helperLib.read_directory.readDirectory();
let Middleware = new helperLib.middleware();
//# require all controllers for this module
let fileObj = ReadDirectory.requireFiles(dir);
//# routes mapping
router
.put('/addprescription', fileObj['prescription.account'].addprescription);
//.get('/prescriptionlist', fileObj['prescription.account'].prescriptionlist)
//.put('/updateprescription', Middleware.decodeToken, fileObj['prescription.account'].updateprescription);
module.exports = {
router: router,
base: '/api/prescription'
};

Please provide the code that is responsible for using validator.js package. The error which occurs is saying that you're probably trying to use validate function from this library which takes only string parameter.
This library validates and sanitizes strings only.
Link: validator.js package usage

Related

Pushing items to array in mongoose

i am trying to create items to specific id of collection using nodejs and mongoose but i am getting CastError which i shared below picture. So goal is, I binded items id in collection schema because collection has many items and when i create items to the specific id of collection i want to push them to items array in the collection schema.
ERROR
ITEMS ROUTE
itemRouter.post("/:collectionId", JWTAuthMiddleware, async (req, res, next) => {
const {name} = req.body
if (req.params.collectionId.length !== 24)
return next(createHttpError(400, "Invalid ID"));
const collection = await CollectionModal.findByIdAndUpdate(
req.params.collectionId,
{
$push : { items: { ...req.body, owner: req.user._id, id: uuidv4() } },
},
{ new: true }
);
if (!collection)
return next(
createHttpError(
400,
`The id ${req.params.collectionId} does not match any collections`
)
);
res.send(collection);
});
Collection schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const collectionSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
image: { type: String },
additionalCustomFields: {
fieldNumber: { type: Number },
fieldName: { type: String },
fieldType: { type: String },
fieldChecked: { type: Boolean },
fieldDate: { type: Date },
},
owner: { type: Schema.Types.ObjectId, ref: "User" },
items: [{ type: Schema.Types.ObjectId, ref: "Item" }],
},
{ timestamps: true }
);
// collectionSchema.index({ "$**": "text" });
export default model("Collection", collectionSchema);
ITEM schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const itemSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
image: { type: String },
comments: [
{
user: { type: Schema.Types.ObjectId, ref: "User", required: true },
text: { type: String },
},
],
tags: { type: String },
owner: { type: Schema.Types.ObjectId, ref: "User" },
likes: [{ type: Schema.Types.ObjectId, ref: "User" }],
collections: { type: Schema.Types.ObjectId, ref: "Collection" },
},
{ timestamps: true }
);
itemSchema.index({ "$**": "text" });
export default model("Item", itemSchema);
Are you sure that using referenced documents is the correct way to go here? Mongoose is complaining because you are trying to push whole objects to the "items" array, instead of ObjectIds of referenced documents.
You have 2 choices here:
1. use embedded documents
This way you can easily store objects directly to the items array, which does not allow you to store the Items in a seperate collection
2. first create Item documents, then push the reference to items array
In this case you have to first create the items in Item collection. Afterwards you can map the result to only ObjectIds and push these to items array of your collection document.

How to insert post method with mongoose having a reference in node.js

I'm using mongoose and have two schema models and one of them "control" has a reference in the fist model which is "framework" model.
With node.js I'm trying to create a post method and testing it in the postman which is not successful. Not sure if I'm approaching this the right way:
Framework Schema:
const FrameworkSchema = new Schema({
name: {
type: String,
trim: true
},
slug: {
type: String,
slug: 'name',
unique: true
},
image: {
data: Buffer,
contentType: String
},
description: {
type: String,
trim: true
},
isActive: {
type: Boolean,
default: true
},
control:
{
type: Schema.Types.ObjectId,
ref: 'Control'
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
My Control schema:
const ControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
mControlNo: {
type: String
},
sControlNo: {
type: String
},
name: {
type: String,
trim: true
},
slug: {
type: String,
slug: 'name',
unique: true
},
description: {
type: String,
trim: true
},
isApplicable: {
type: Boolean,
default: true
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
My router api:
router.post(
'/add',
auth,
role.checkRole(role.ROLES.Admin),
async (req, res) => {
try {
const name = req.body.name;
const description = req.body.description;
const isActive = req.body.isActive;
const control = {
mControlNo: req.body.control.mControlNo,
sControlNo: req.body.control.sControlNo,
name: req.body.control.name,
description: req.body.control.description,
isApplicable: req.body.control.isApplicable
};
const framework = new Framework({
name,
description,
isActive,
control
});
const frameworkDoc = await framework.save();
res.status(200).json({
success: true,
message: `Framework has been added successfully!`,
framework: frameworkDoc
});
} catch (error) {
res.status(400).json({
error
// error: 'Your request could not be processed. Please try again.'
});
}
}
);
My json document when I tested it in postman:
{
"name": "NCA2",
"description": "testdescription",
"isActive": true,
"control":
{
"mControlNo": "1",
"sControlNo": "2",
"name": "controltest",
"description": "controldescription",
"isApplicable": true
}
}
Response I'm getting:
{
"error": {
"errors": {
"control": {
"stringValue": "\"{\n mControlNo: '1',\n sControlNo: '2',\n name: 'controltest',\n description: 'controldescription',\n isApplicable: true\n}\"",
"kind": "ObjectId",
"value": {
"mControlNo": "1",
"sControlNo": "2",
"name": "controltest",
"description": "controldescription",
"isApplicable": true
},
"path": "control",
"reason": {}
}
},
"_message": "Framework validation failed",
"message": "Framework validation failed: control: Cast to ObjectId failed for value \"{\n mControlNo: '1',\n sControlNo: '2',\n name: 'controltest',\n description: 'controldescription',\n isApplicable: true\n}\" at path \"control\""
}
}
The whole point of using a framework like mongoose is to write models and let the framework check for you if the body you're sending it is right or wrong. You don't have to assign each variable from your body to your model. You can simply write the following, which will save lines:
const framework = new Framework(req.body);
(Of course, granted that the body has been correctly parsed to JSON via body-parser or another parser).
Then, you check for description or name to be present:
if (!description || !name)
but none of them exist. req.body.description and req.body.name do exist, possibly framework.description and framework.name do as well, but description or name are undefined variables.
The rest of the code looks good, if the error persists, please print out the error in the catch clause as others have suggested in the comments.
Following the code added in the question and the comments the OP made, we now have more elements to answer.
You have a ValidationError coming from mongoose, meaning one of the field you entered is not right. You can also see that it's coming from the field control.
In your Framework schema, you declare a field control that looks like that:
control:
{
type: Schema.Types.ObjectId,
ref: 'Control'
},
That means that Framework is taking an ObjectID for this field, and not an object like you send it here:
const framework = new Framework({
name,
description,
isActive,
control
});
The error is explicit on its own: Mongoose tried to cast your control object to an ObjectID and of course, it fails.
You have 2 solutions:
Either you implement your Control schema directly in your Framework schema as an object field
Or you create a separate Schema object in your route, save it, and give the ID to control when creating the Framework object.
The second solution could look something like this:
const control = new Control(req.body.control);
const controlDoc = await control.save();
const framework = new Framework({...req.body, control: controlDoc._id});
const frameworkDoc = await framework.save();
The first could look something like this:
const FrameworkSchema = new Schema({
// all your Framework schema
control:
{
mControlNo: { type: String },
sControlNo: { type: String },
name: { type: String, trim: true},
// and so on....
},
});

Mongoose find recursive nested object by id

I'm building a note taking app in which there can be as many nested notes inside one another as the user wants, Similar to folder and file structure expect here everything is a note, I have a note model inside it there is a sub_notes array, I want to be able to find a note whether it is a note at the top of the document or nested inside the sub_notes array, I'm passing the id of the note to which I want to add the next note, I have tried graphlookup but when I use the query it is returning an empty array
This is my Note model
const noteSchema = new Schema({
icon: {
type: String,
},
banner: {
type: String,
},
name: {
type: String,
required: true,
},
user_id: {
type: String,
required: true,
},
date: {
type: Date,
required: true,
default: Date.now,
},
sub_notes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "notes",
},
],
content: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "blocks",
},
],
});
module.exports = Note = mongoose.model("notes", noteSchema);
This is the query I'm using to find the nested note, The path is a dot seperated string with ids of the notes & the note is the actual note object with the name and other data.
So for ex:
The note
{
id: "123123123",
sub_notes: [{
id: "xyz"
}]
}
So the path here will be 123123123.xyz
var {
note,
path
} = req.body;
var newPath = path.split(".");
const parentNote = Note.findById(newPath[0]);
newPath.splice(0, 1);
console.log(newPath[newPath.length - 1]);
Note.aggregate([{
$match: {
$id: newPath[newPath.length - 1]
}
},
{
$graphLookup: {
from: "notes",
startWith: "$id",
connectFromField: "sub_notes",
connectToField: "id",
depthField: "level",
as: "sub_notes",
},
}
]).exec((err, notes) => {
console.log(notes);
});

I tried to find the user from the mongoose db

This is my mongoose schema for movieLibrary
const mongoose = require('mongoose')
const movieSchema = new mongoose.Schema({
movieName:{
type: String,
required: true,
trim: true
},
movieCast:[{
actor:{
type: String,
required: true
},
actress:{
type: String,
required: true
}
}],
yearOfRelease:{
type : Date,
default : Date.now
},
movieDirector:{
type: String,
required: true
},
genre:{
type: String,
required: true
},
rating:{
type: Number,
required: true
}
})
module.exports = mongoose.model('movieLibrary',movieSchema)
I want to find the movie detail by passing the actor name as a parameter
I tried this:-
const movies = await Movie.find({
"movieCast": {
$elemMatch: {
"actor": actor
}
}
})
But i get empty array as the output , Can you help me what issue might have occured , I get the correct answer in robo 3T, but not getting in postman.
I don't see anything wrong in your implementation. I have done the same thing like you except I have hard coded the value in query itself. It's working fine for me.
Data which is available in DB,
{
"_id" : ObjectId("5ed9c47b39d18ba11f4c8f10"),
"movieName" : "Titanic",
"movieCast" : [
{
"actor" : "Leonardo",
"actress" : "Winslet"
}
],
"yearOfRelease" : ISODate("1994-04-01T23:20:19.199Z"),
"movieDirector" : "James Cameroon",
"genre" : "History",
"rating" : 8.8
}
And the query impl,
async test() {
let result = await Test.find({
"movieCast": {
$elemMatch: {
"actor": 'Leonardo'
}
}
});
console.log(JSON.stringify(result));
return result;
}
I think either you could have passed the wrong actor value or none is passed.

Mongoose populate() returns empty array with no errors

I've been trying to get this populate thing to work, but I'm getting issues because I am not getting the expected results, and no errors to work with. Just simply an empty array.
My models look like this. Each their own file
var mongoose = require( 'mongoose' );
var upgradeSchema = new mongoose.Schema({
type: {
type: String,
default: "Any"
},
ability: String,
ability_desc: String,
level: Number,
tag: String
});
mongoose.model('Upgrade', upgradeSchema);
and the other
var mongoose = require( 'mongoose' );
var crypto = require('crypto');
var jwt = require('jsonwebtoken');
var userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
hero: {
level: Number,
name: String,
type: {
path: String,
heroType: String
},
upgrades: [{
type: mongoose.Schema.Types.ObjectId, ref: 'Upgrade'
}],
unspent_xp: Number,
total_xp: Number,
},
armyTotal: {
type: Number,
default: 0,
max: 5000
},
army:[{
foc_slot: String,
unit_name: String,
unit_cost: Number
}],
username: {
type: String,
required: true,
unique: true,
},
faction: String,
name: {
type: String,
required: true
},
hash: String,
salt: String,
roles: {
type: String,
default: 'player' }
});
And I'm trying to do this
module.exports.profileRead = function(req, res) {
User
.findById(req.payload._id)
.populate('hero.upgrades')
.exec(function (err, user) {
if (err){
console.log(err);
} else {
res.status(200).json(user);
console.log("success");
}
});
}
};
This is an example of a user
{
"_id" : ObjectId("57b4b56ea03757e12c94826e"),
"hash" : "76",
"salt" : "2",
"hero" : {
"upgrades" : [
"57b42773f7cac42a21fb03f9"
],
"total_xp" : 0,
"unspent_xp" : 0,
"type" : {
"heroType" : "Psyker",
"path" : ""
},
"name" : "Jon Doe"
},
"username" : "michaelzmyers",
"faction" : "Grey Knights",
"email" : "email#gmail.com",
"name" : "Michael Myers",
"roles" : "player",
"army" : [],
"armyTotal" : 625,
"__v" : 3
}
Now, I've tried an array of just the strings with ObjectId's in them, similar to the eample, and I've also tried using ObjectId("STRINGHERE") and no luck. They both return just an empty array. However, if i get rid of the populate call (or change the contents inside populate from hero.upgrades to just hero, or upgrades) then it just returns an array of strings. I feel like the problem is with populate and how I'm using it. HOWEVER, when I had just a single upgrade in my databse (the test upgrade), everything worked fine. Now nothing works. Any thoughts? I'd be happy to provide more code if needed.
I found that during my little research that it will work:
User
.findById(req.payload._id)
.populate({
path: 'hero.upgrades',
model: 'Upgrade'
})
.exec(function (err, user) {
if (err){
console.log(err);
} else {
res.status(200).json(user);
console.log("success");
}
});
}
It looks like when user is giving nested object notation i.e. hero.upgrades into populate method, Mongoose got problems with detecting referring model.

Resources