How to save array of objects in mongoose? - node.js

Hi so i have an array of objects that look like this
[{
"id": 0,
"name": "Del Vecchios | Italian Food | Asheville, NC",
"domain": "delvecchiositalian.com",
"email": "eat#delvecchiositalian.com",
"phone": "828-258-7222",
},
{
"id": 1,
"name": "DeRango's Pizza Palace | Italian Restaurant | Racine, WI",
"domain": "derangos.com",
"email": "info#derangospizzapalace.com",
"phone": "262-639-4112",
},
{
"id": 2,
"name": "Michigan's Premier Flooring Installation Services | D.E. McNabb",
"domain": "demcnabb.com",
"email": "no email",
"phone": "(248) 587-1500",
},
}]
And i want to store it in my mongo database but i dont know how to make the schema, my actual schema looks like this
const mongoose = require("mongoose");
const infoSchema = new mongoose.Schema(
{
info: {
type: String,
trim: true,
required: true,
maxlength: 3200
}
},
{ timestamps: true }
);
module.exports = mongoose.model("ScrapedInfo", infoSchema);
and this is the controller for saving the data
router.post('/stored', (req, res) => {
const info = new ScrapedInfo(req.body)
info.save((err) => {
if (err) {
console.log(err+"error")
}
else{
console.log('saved')
}
});
});
Dunno if i am making a mistake in the controller, seems fine to me, but i every time i run the button for the controller, i have the rror ValidationError: info Path info is required

When trying to update an array of objects, using mongoose, you will have to tell MongoDB that there are pending changes by using the markModified(path) method. after this you will have to call the save() method.
example
We have the passwordsArr part of the schema as an array of objects.
// passwordsArr modified
// mark the path as having changes to write to the DB
user.markModified('passwordsArr');
// now saves the document user.save(function (err, user) { if (err) return next(err);

Your schema should look something like this. The "Path info is required error" is caused by the fact that the key "info" doesn't exist in the Schema.
const mongoose = require('mongoose')
const Schema = mongoose.Schema
// Schema
const infoSchema = new Schema(
{
name: {
type: String,
required: true,
},
domain: {
type: String,
required: true
},
email: {
type: String,
required: true
},
phone: {
type: String,
required: true
}
},
{ timestamps: true }
)
// Model
module.exports = mongoose.model('Info',infoSchema)
If you want to save an array your "info" key should look like this:
info: {
type: Array,
trim: true,
required: true,
maxlength: 3200
}
Where the "type" is Array instead of String.

Related

how to populate a mongoose schema on one by one

I trying populate a mongoose schema.
i have 3 schema named clothBrandSchema, clothSchema,userSchema.
clothBrandSchema :
name: {
type: String,
required: true,
},
Origin: String,
}
const ClothBrand = new mongoose.model("ClothBrand", ClothBrandSchema);
second is:
clothSchema:
{
category: {
type: String,
enum: ["Ladies", "Mens","Kids","Boys","Girls"],
},
name: String,
brand:[{
type:mongoose.Schema.Types.ObjectId,
ref:"ClothBrand"
}] //many brands have same type of cloth so define array of brands name
}
const Cloth = new mongoose.model("Cloth", clothSchema);
third is:
userSchema:
{
name: {
type: String,
required: true
},
cloth: {
type:mongoose.Schema.Types.ObjectId,
ref:"Cloth"
}
}],
}
const User = new mongoose.model("User", userSchema);
so i want to when i get data of user then i got like this:
User:
{
"_id": "62df18bdb19a5a056a18c0c9",
"name": "ABC",
"cloth": {
"_id": "62df12525e2c53efd6afe2c5",
"category": "Boys",
"name": "Jeans",
"brand":[
{
"name": "xyz"
"Origin": "xyz"
},
{
"name": "xyz"
"Origin": "xyz"
}
...
] // somewhere not written an object id so ignore it
},
so is it possible then what is solution. how can i Write Query in my node js Code Base.
I got an answer in few hours from mongoose offical documentaion mongoose docs on populate
so the code is like that:
user.findOne({ name: 'ABC' }).
populate({
path: 'Cloth',
populate: { path: 'brand' }
})
.then(result => {
res.json(result)
})

{"index": 0,"code": 11000,"keyPattern": {"Name": 1}, "keyValue": { "Name": null }} error on adding second product to database

On trying to add a product to my database using the following method,
//ADD PRODUCT
router.post("/addproduct", verifyTokenAndAdmin, async (req, res) => {
const newProduct = new Product(req.body);
try {
console.log("req for pdt add");
const savedProduct = await newProduct.save();
console.log("pdt added successfully");
res.status(200).json(savedProduct);
} catch (err) {
res.status(500).json(err);
}
});
Mongoose is throwing this error when adding the second product. The first product is successful always but cannot make a second post request and also put request to update the product details is not working, but the delete request works perfectly fine
{
"index": 0,
"code": 11000,
"keyPattern": {
"Name": 1
},
"keyValue": {
"Name": null
}
}
Given below is my product schema
const { default: mongoose } = require("mongoose");
const ProductSchema = new mongoose.Schema(
{
title: { type: String, required: true, unique: true },
desc: { type: String, required: true },
img: { type: String, required: true },
category: { type: Array, required: true },
size: { type: String },
color: { type: String },
price: { type: Number, required: true },
},
{ timestamps: true }
);
module.exports = mongoose.model("Product", ProductSchema);
Because in your MongoDB field "name" have Properties UNIQUE at the field "Indexes". And you have to drop that property or you never can create the same name value even if it a empty value.
I used to have the same error, and this is my resolution for the issue:
This error comes as a result of a model waiting to receive data that should actually come from the body of the request, but because it cannot read it because you did not add the middleware app.use(express.json()). Therefore, it creates the index but without all the data.

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....
},
});

Trouble generating unique UUIDv4 at model instanciation

I am having an issue related to UUID when trying to create an instance of mongoose model.
Mongoose Schema
export interface IRessourceModel extends IRessource, mongoose.Document { }
export let RessourceSchema: mongoose.Schema = new Schema({
uuid: {
type: String,
default: uuidv4() },
name: {
type: String,
required: true,
minlength: RessourceValidation.CONSTANTS.NAME_MIN_LENGTH,
maxlength: RessourceValidation.CONSTANTS.NAME_MAX_LENGTH,
trim: true,
validate: {
validator: RessourceValidation.name,
message: '{VALUE} is not a valid name'}},
type: {
type: String,
required: true,
enum: RessourceValidation.ENUM.TYPE,
validate: {
validator: RessourceValidation.type,
message: '{VALUE} is not a valid type'}},
uploaded: {
type: Date,
required: true,
default: Date.now }
})
export const Ressource: mongoose.Model<IRessourceModel> = mongoose.model<IRessourceModel>('Ressource', RessourceSchema);
Instanciation
const RessourceModel = mongoose.model('Ressource');
// Some code here...
let Ressource: any = new RessourceModel({
name: req.body.name,
type: req.body.type,
})
Ressource.save((err, ressource) => {
if (err)
return (APIResponse.jsonErrorAfterMongooseQuery(res, 'Cannot create ressource', err));
APIResponse.json(res, ressource);
})
Issue
When I'm sending a POST request on /ressources/ which is using the piece of instanciation code above, the ressource is created but, if I send another POST request, the second ressource created has the same UUID than the first one...
Results for POST request #1
{
"type": true,
"data": {
"uuid": "1794bbb4-3385-4b0d-909a-e22c60aee608",
"_id": "5b3a42f5ae71a02af4ed6d11",
"name": "Name of ressource 1",
"type": "IMAGE",
"uploaded": "2018-07-02T15:21:25.866Z",
"__v": 0
}
}
Results for POST request #2
{
"type": true,
"data": {
"uuid": "1794bbb4-3385-4b0d-909a-e22c60aee608",
"_id": "5b3a4530f3ab1f3d40b7ac93",
"name": "Name of ressource 2",
"type": "IMAGE",
"uploaded": "2018-07-02T15:30:56.379Z",
"__v": 0
}
}
Am I using the default: uuidv4() wrongly or is it coming from the way I instanciate the mongoose model ? Or anything else ?
I do have tried to set the UUID from the Schema.pre('save') function but without success...
I'm a bit lost, thanks for your help !
It seems that uuidv4() is a string. Of course, it will be same in all models.
Considering that:
const uuidv4 = require('uuidv4');
Mongoose default schema option can accept a function to generate a value:
export let RessourceSchema: mongoose.Schema = new Schema({
uuid: {
type: String,
default: uuidv4
},
...

Unable insert more than 1 entry in MongoDB

Here is my schema. user_id and other_id are supposed to be unique (composite).
var mongoose = require("mongoose");
var uniqueValidator = require('mongoose-unique-validator');
var Schema = mongoose.Schema;
var FriendshipSchema = new Schema({
user_id: {
type: String,
default: "",
trim: true,
unique:true,
},
other_id: {
type: String,
default: "",
unique:true,
},
status: {
type: String,
index: true,
default: "none",
},
});
FriendshipSchema.plugin(uniqueValidator);
module.exports = mongoose.model('Friendship', FriendshipSchema)
and here is my server-side code. pretty straightforward insert using Mongoose.
app.post('/api/user/friendrequest', function(req, res){
var friendship = new Friendship(req.body);
console.log(req.body);
Friendship.find({}, function (err, docs) {
if (docs.length){
console.log('abac');
}else{
friendship.save(function(err){
if (err)
{
console.log(err)
}
});
}
});
});
I get this response in console but no more than 1 entry is saved in MongoDB. I've deleted indexes as well and its still not working. btw 'user_id' is unique in another Collection. I also don't get any error when i log console.log(err).
{ user_id: 'google-oauth2|117175967810648931400',
status: 'pending',
other_id: 'facebook|10209430751350509' }
abac
Here are the indexes for the friendships collection.
db.friendships.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "kola.friendships"
}
]
What you want is the "combination" of fields to be "unique" here rather than be treated individually as such.
That means your schema should instead be defined like this:
var FriendshipSchema = new Schema({
user_id: {
type: String,
default: "",
trim: true,
},
other_id: {
type: String,
default: "",
},
status: {
type: String,
index: true,
default: "none",
},
});
// Instead define the schema level index here
FriendshipShema.index({ "user_id": 1, "other_id": 1 },{ "unique": true });
module.exports = mongoose.model('Friendship', FriendshipSchema);
The best part of this is that you don't need any plugin to support what you want to do.
Please do make sure you run a .dropIndexes() on the collection to get rid of any individual "unique" indexes that will interfere with the correct operation.
Also see .createindex() and "Unique Indexes" in the core documentation for more information.

Resources