Trouble generating unique UUIDv4 at model instanciation - node.js

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

Related

Updating array of objects inside an object mongodb node

I have a mongoDb model defined as follows:-
var mongoose = require("mongoose");
const postModel = new mongoose.Schema({
postId: {
type: String,
unique: true,
required: true
},
authorId: {
type: String,
required: true
},
post: {
authorHandle: {
type: String,
required: true
},
heading: {
type: String,
required: true
},
message: {
type: String,
required: true
},
creationDate: {
type: Date,
required: true
},
image: { type: Array },
video: { type: Array },
comments: {
type: Array
}
}
});
module.exports = mongoose.model("postModel", postModel);
Now I have a sample value of a document of the above model, suppose:-
postId: "aaa",
authorId: "bbb",
post: {
authorHandle: "someone#123",
heading: "hello",
message: "post 1",
creationDate: "some creation date string(please ignore this is irrelevant to my question)",
image: [],
video: [],
comments: [
{ commentId: "1", message: "Something", createdAt: sometime },
{ commentId: "2", message: "Something else", createdAt: sometime2 },
{ commentId: "3", message: "Something other", createdAt: sometime3 },
]
}
Now say the user wants to update the comment with commentId 2 of this post with postId "aaa". My question is that what is the best way to use the findOneAndUpdate() method to solve this problem?
const PostModel = require("./models/PostModel"); //just importing the model that is defined above
//the below is happening inside a request handler in Node + Express
PostModel.findOneAndUpdate(
//what to do here
)
What I have tried is pulling out that whole object and replacing it with a new object with the new message. But that doesnt seem like a very efficient way. Any and all help is greatly appreciated!
You should write:
const updatedPost = await PostModel.findOneAndUpdate(
{ postId: 'aaa', 'post.comments.commentId': 2 },
{ 'post.comments.$.message': 'Updated message'},
{ new: true }
)

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

Creating sub-module in MongoDB while loading test data from json file

I am trying to load default data into my MongoDB database from a node.js backend.
This is the data I am loading as JSON:
[
{
"datetime": "28/08/2021 16:01:00",
"sensor": {
"id": 1,
"type": "Temperature"
},
"value": 2502
},
{
"datetime": "28/08/2021 16:02:00",
"sensor": {
"id": 2,
"type": "Temperature"
},
"value": 2252
}
]
And these are the mongoose models:
const SensorType = Object.freeze({
Temperature: "Temperature"
});
const SensorSchema = new mongoose.Schema({
id: { type: Number, required: true },
type: { type: Object.values(SensorType), required: true },
});
Object.assign(SensorSchema.statics, { SensorType });
const Sensor = mongoose.model('Sensor', SensorSchema);
const DataEntrySchema = new mongoose.Schema({
datetime: { type: String, required: true },
sensor: { type: SensorSchema, required: true },
value: { type: Number, required: true }
});
const DataEntry = mongoose.model('DataEntry', DataEntrySchema);
Loading the DataEntries like this:
mongoose.connect("mongodb://127.0.0.1:27017/",{
useCreateIndex:true,
useNewUrlParser: true,
useUnifiedTopology: true}
).then(() => {
console.log('Database Successfully Connected')
if(fill_default_data) {
DataEntry.create(
JSON.parse(fs.readFileSync(path.resolve(__dirname, 'test_data.json'), 'utf8'))
);
}
}, error => {
console.log(error)
}
);
However, I am noticing that no Sensor-objects are created inside MongoDB, only DataEntries - why is that? And how can I create Sensor-objects as well?
Of course, a DataEntry object has the sensor attached but if I call Sensor.find().then( sensors => res.json(sensors) ) an empty array is returned.
You probably can't use a schema in another schema. You need to use refs instead.
So something like this sensor: { type: SensorSchema, required: true } won't work.
You should replace it with sensor: { type: number, required: true, ref: 'Sensor' },, where the ref is the name of the model you want to refer to as a string. Notice that the type is a number as you want to pass the id of the relevant SensorDocument in the DataEntryDocument.
Moreover id is a virtual, you should use _id instead when you want to spec out ids in mongoose schemes.
So your mongoose schemes should look like:
const SensorSchema = new mongoose.Schema({
_id: { type: mongoose.Schema.Types.Number, required: true },
type: { type: mongoose.Schema.Types.String, required: true },
});
const Sensor = mongoose.model('Sensor', SensorSchema);
const DataEntrySchema = new mongoose.Schema({
datetime: { type: mongoose.Schema.Types.String, required: true },
sensor: { type: mongoose.Schema.Types.Number, ref: 'Sensor', required: true },
value: { type: mongoose.Schema.Types.Number, required: true }
});
const DataEntry = mongoose.model('DataEntry', DataEntrySchema);
I still don't know why the Object.freeze and Object.assign are here.
Now if you want a DataEntry, you first need to create a Sensor.
const sensor = new Sensor({ _id: 0, type: 'Temperature' })
await sensor.save()
const dataEntry = new DataEntry({ sensor: 0, datetime: 'some timestamp as string', value: 25 })
await dataEntry.save()
I am leaving the validation-specific logic out as it is out of the scope of this query.
You can checkout docs for mongoose populate for more information.

How to save array of objects in mongoose?

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.

Resources