I have Encomenda that has an array of Itens. Itens can have an array of itens.
I have the following code:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
var idvalidator = require('mongoose-id-validator');
let ItemSchema = new Schema({
produtoId:Number,
itens:[{type:Schema.Types.ObjectId, ref: 'Item'}]
});
function autoPopulateItens(next){
this.populate('itens');
next();
}
ItemSchema
.pre('findOne',autoPopulateItens)
.pre('find',autoPopulateItens);
module.exports=mongoose.model('Item',ItemSchema);
let EncomendaSchema= new Schema({
itens:[ItemSchema]
});
module.exports=mongoose.model('Encomenda',EncomendaSchema);
function log(data){
console.log(JSON.stringify(data,undefined,2))
}
And I'm trying to make a post request on postman to create an Encomenda with the following code:
{
"itens":[{
"produtoId":5,
"itens":[{
"produtoId":6,
"itens":[]
},{
"produtoId":7,
"itens":[]
},{
"produtoId":8,
"itens":[]
}]
}
]
}
But when I try to create an Encomenda and save it to the mongodb it gives me an error:
CoreMongooseArray [ { itens: [], _id: 5bd9fde20c29e35f2c0ca74a, produtoId: 5 } ]
ValidationError: Encomenda validation failed: itens.0.itens: Cast to Array failed for value "[ { produtoId: 6 },
{ produtoId: 7, itens: [] },
{ produtoId: 8, itens: [] } ]" at path "itens"
at new ValidationError (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\error\validation.js:30:11)
at model.Document.invalidate (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\document.js:2026:32)
at EmbeddedDocument.invalidate (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\types\embedded.js:289:19)
at EmbeddedDocument.$set (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\document.js:989:10)
at EmbeddedDocument._handleIndex (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\document.js:773:14)
at EmbeddedDocument.$set (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\document.js:719:22)
at EmbeddedDocument.Document (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\document.js:115:12)
at EmbeddedDocument [as constructor] (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\types\embedded.js:39:12)
at new EmbeddedDocument (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\schema\documentarray.js:75:17)
at DocumentArray.cast (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\schema\documentarray.js:334:22)
at DocumentArray.SchemaType.applySetters (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\schematype.js:763:12)
at model.$set (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\document.js:981:18)
at model._handleIndex (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\document.js:773:14)
at model.$set (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\document.js:719:22)
at model.Document (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\document.js:115:12)
at model.Model (D:\ISEP\3º\ARQSI\pr2\node_modules\mongoose\lib\model.js:90:12)
this how I try to create and save an Encomenda:
exports.encomenda_create = function (req, res,next) {
var Client = require('node-rest-client').Client;
var client = new Client();
let encomenda=new Encomenda(req.body);
encomenda.save(function (err) {
if (err) {
return next(err);
}
res.send('encomenda criada com sucesso')
})
};
Pass next as a parameter into your function like so:
exports.encomenda_create = function (req, res, next) {
Related
I'm trying to push data to a nested array in mongodb. I'm using mongoose as well.
This is just mock code to see if i can get it working:
User model:
import mongoose from "mongoose";
const CoinSchema = new mongoose.Schema({
coinID: { type: String },
});
const CoinsSchema = new mongoose.Schema({
coin: [CoinSchema],
});
const WatchlistSchema = new mongoose.Schema({
watchlistName: { type: String },
coins: [CoinsSchema],
});
const NameSchema = new mongoose.Schema({
firstName: { type: String },
lastName: { type: String },
username: { type: String },
});
const UserSchema = new mongoose.Schema({
name: [NameSchema],
watchlists: [WatchlistSchema],
test: String,
});
const User = mongoose.model("User", UserSchema);
export default User;
route:
fastify.put("/:id", async (request, reply) => {
try {
const { id } = request.params;
const newCoin = request.body;
const updatedUser = await User.findByIdAndUpdate(id, {
$push: { "watchlists[0].coins[0].coin": newCoin },
});
await updatedUser.save();
// console.dir(updatedUser, { depth: null });
reply.status(201).send(updatedUser);
} catch (error) {
reply.status(500).send("could not add to list");
}
});
request.body // "coinID": "test"
I've tried a lot of different ways to push this data but still no luck. I still get 201 status codes in my terminal which indicates something has been pushed to the DB, but when I check nothing new is there.
Whats the correct way to target nested arrays and push data to them?
It's not perfect but you could get the user document, update the user's watchlist, and then save the updated watchlist like so:
fastify.put("/:id", async (request, reply) => {
try {
const { id } = request.params;
const newCoin = request.body;
// get the user
let user = await User.findById(id);
// push the new coin to the User's watchlist
user.watchlists[0].coins[0].coin.push(newCoin);
//update the user document
const updatedUser = await User.findOneAndUpdate({ _id: id },
{
watchlists: user.watchlists,
},
{
new: true,
useFindAndModify: false
}
);
reply.status(201).send(updatedUser);
} catch (error) {
reply.status(500).send("could not add to list");
}
});
I created a program for CRUD but facing issues
Controller program :-
const Greeting = require("../models/model.js");
exports.create = (req, res) => {
if (!req.body.message) {
return res.status(400).send({ message: "Note content can not be empty" });
}
const greeting = new Greeting({
name: req.body.name || "Name Needed",
message: req.body.message,
});
Greeting.pushData(greeting);
};
modules.js
const GreetingSchema = mongoose.Schema(
{
name: String,
message: String,
},
{
timestamps: true,
}
);
module.exports = mongoose.model("Greeting", GreetingSchema);
const Schema = mongoose.model("Greeting", GreetingSchema);
pushData = (greeting) => {
const data = new Schema({
name: greeting.name,
message: greeting.message
});
data
.save()
.then((data) => {
res.send(data);
})
.catch((err) => {
res
.status(500)
.send({
message: err.message || "Error Occurred while creating Greeting",
});
});
}
module.exports = {pushData};
and getting errors:
*
TypeError: Greeting is not a constructor
at exports.create (E:\Projects\Greeting-App_backend - Copy\controller\controller.js:9:20)
at Layer.handle [as handle_request] (E:\Projects\Greeting-App_backend - Copy\node_modules\express\lib\router\layer.js:95:5)
at next (E:\Projects\Greeting-App_backend - Copy\node_modules\express\lib\router\route.js:137:13)*
There are few errors in your code.
pushData method should be part of Schema if you want to keep it inside models and access through model Schema. No need to export pushData if you do it like below.
GreetingSchema.methods.pushData = (greeting) => {
// your code
}
module.exports = mongoose.model("Greeting", GreetingSchema);
In controller it will be -
greeting.pushData(greeting);
The error shows that your Greeting model is not a constructor. Check your model again to see if it's in the right format of how to create constructor in Javascript.
function Greeting(greeting) {
this.name = greeting.name;
this.message = greeting.message;
}
I want to create a schema, with arrays for names of participants at an event, I make the list of participants by doing so:
quizPart:[{
type:String,
}]
How can I validate that the length of this array is either zero (no participants at this event) or 2, and not 1 (it is a two people per team event). I want to return an error message that I can handle with ValidationError
I am adding data to this schema like so:
var school = new School();
school.quizPart=req.body.quiz;
where req.body.quiz = ["name1","name2"] or ['','']
and then, if only 1 field has a string value, I want to parse an error to the repsonse body like so:
function handleValidationError(err, body) {
for (field in err.errors) {
switch (err.errors[field].path) {
case "quizPart":
body["quizPartError"] = err.errors[field].message;
break;
}}}
This is a working example of what I mean to say.
Write a pre('update') mongoose hook and inspect the $set object if the quizParts field has length 0 or 2 or not.
index.js
const mongoose = require('mongoose');
const test = require('./test');
mongoose.connect('mongodb://localhost:27017/test2', {useNewUrlParser: true});
mongoose.set('debug',true);
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
// we're connected!
});
(async() => {
try {
const testUpdate = test();
const updateQuery = {
$set: {
quizPart: [
{
type: 'Type 1'
},
{
type: 'Type 2'
}
]
}
};
const updateResult = await testUpdate.update({}, updateQuery).exec();
} catch(err) {
console.error(err);
}
})();
test.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
module.exports = function() {
const testSchema = new Schema({
quizPart: [
{
type: String,
}
]
},
{
collection: 'test',
timestamps: true
});
testSchema.pre('update', function(next) {
const update = this._update.$set;
if (update.length === 0 || update.length === 2) {
return next();
}
else {
return next(new Error('Cannot have length 1!'));
}
});
return mongoose.model('test', testSchema);
};
Made the field:
quizPart:[{
type:String,
}],
And then verified the field by:
schoolSchema.path('quizPart').validate((list)=>{
alNumRegex= /^[a-z0-9]+$/i
return list[0]!=="" && list[1]!=="" || alNumRegex.test(list[0]) && alNumRegex.test(list[1]);
},'Please Register atleast two participants for quiz.');
I have defined a schema for add question and its like
var mongoose = require('mongoose');
var questionSchema = new mongoose.Schema({
question_set : String,
questions:[{
question_id : String,
question_no : Number
}]
});
I would like to insert variables say, ques_set = 'xyz' and an array question_array = [['id_1',1],['id_2',2],['id_3',3]].
I used this code to insert to mongodb
var questions = require('../schemas/questions');
exports.testing = function(req,res){
if (!req.body) return res.sendStatus(400)
var ques_set = 'xyz';
var question_array = [['id_1',1],['id_2',2],['id_3',3]];
var data = question({ques_set,question_array);
data.save(function(err) {
if (err) throw err;
else {
console.log('Question Inserted');
res.send("Question Inserted");
}
});
};
This shows me an error TypeError: object is not a function. Please help me, I just started nodejs. Thanks
You need to create a question object that matches your schema, something like this:
var Question = require('../schemas/questions');
exports.testing = function(req,res){
if (!req.body) return res.sendStatus(400)
var ques_set = 'xyz';
var question_array = [
{
question_id: "id_1",
question_no: 1
},
{
question_id: "id_2",
question_no: 2
},
{
question_id: "id_3",
question_no: 3
}
];
var data = Question({question_set: ques_set, questions: question_array});
data.save(function(err) {
if (err) throw err;
else {
console.log('Question Inserted');
res.send("Question Inserted");
}
});
};
I have a mongoose schema with a subdocument. Both the parent schema and the child schema have pre save hooks. For example:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var SubSchema = new Schema( { x : Number } );
SubSchema.pre('save', function (next) {
console.log("pre save Sub");
next();
});
var MainSchema = new Schema( { x : Number, children : [SubSchema] } );
MainSchema.pre('save', function (next) {
console.log("pre save Main");
next();
});
var Main = mongoose.model('Main', MainSchema);
var m = new Main();
m.children.push( { x : 42 } );
m.save( function(err, doc) {
console.log(doc +"\n\n");
doc.children[0].x = 43;
doc.save( function(err, doc2) {
console.log(doc2 + "\n\n");
});
});
When I run this code, I get the following output:
pre save Sub
pre save Main
{ __v: 0,
_id: 50660b319aec895a50000002,
children: [ { x: 42, _id: 50660b319aec895a50000003 } ] }
pre save Main
{ __v: 0,
_id: 50660b319aec895a50000002,
children: [ { x: 43, _id: 50660b319aec895a50000003 } ] }
Any reason why the pre save hook is not running for the subdocument on the second save operation?
This is fixed in v3.2.0, by letting you do this:
doc.children.set(0, {x: 43})
doc.save()