How to add a javascript array variable into mongodb using node - javascript

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

Related

Mongoose validate length of array in schema

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.');

remove array element with remove() is not working?

I have used the below code in my API to remove element from an array
deleteCommentLike: async(req, res) => {
const { error } = createComLikeValidation(req.body);
if (!error) {
const { user_id, comment_id } = req.body;
// const likeModel = new likeSchemaModel({user_id: user_id, post_id: post_id});
await commentlikeSchemaModel
.find({ user_id: user_id, comment_id: comment_id })
.remove();
let commenttData = await commentSchemaModel.findById(comment_id);
console.log(commenttData.usersLiked);
commenttData.likes = --commenttData.likes;
commenttData.usersLiked.remove(user_id);
await commenttData.save();
res.status(200).json({ error: false, data: "done" });
} else {
let detail = error.details[0].message;
res.send({ error: true, data: detail });
}
},
In here this one line is not working: commenttData.usersLiked.remove(user_id);. It doesn't give any error but the user_id is not removed from my database.
"use strict";
const mongoose = require('mongoose');
const Joi = require('joi');
var commentSchema = mongoose.Schema({
//other data
usersLiked: [{
type: mongoose.Types.ObjectId,
default: []
}],
//other data
}
var commentSchemaModel = mongoose.model('comments', commentSchema);
module.exports = {
commentSchemaModel,
}
In my mongodb it looks like below
I have alredy tried using it as commenttData.usersLiked.remove(mongoose.Types.ObjectId('user_id'));
but the result is same.
What can be the reason for this and how could I remove the value from the array ?
You should use an update operation:
commenttData.update({_id: mongoose.Types.ObjectId("5f099..")}, {$set: {usersLiked: yourUpdatedUsersLikedArray}})
The error you expect from remove() is missing as you trigger a js noop which is just ignored by the compiler.
Mongoose does not implement the attribute update operation the way you use it.

ReferenceError: next is not defined

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) {

Write / add data in JSON file using Node.js

I am trying to write JSON file using node from loop data, e.g.:
let jsonFile = require('jsonfile');
for (i = 0; i < 11; i++) {
jsonFile.writeFile('loop.json', "id :" + i + " square :" + i * i);
}
outPut in loop.json is:
id :1 square : 1
but I want output file like this (below) and also if I run that code again it should add that new output as elements in same existing JSON file:
{
"table":[
{
"Id ":1,
"square ":1
},
{
"Id ":2,
"square ":3
},
{
"Id ":3,
"square ":9
},
{
"Id ":4,
"square ":16
},
{
"Id ":5,
"square ":25
},
{
"Id ":6,
"square ":36
},
{
"Id ":7,
"square ":49
},
{
"Id ":8,
"square ":64
},
{
"Id ":9,
"square ":81
},
{
"Id ":10,
"square ":100
}
]
}
I want to use same file that I created 1st time but whenever I run that code new elements should add in that same file
const fs = require('fs');
let obj = {
table: []
};
fs.exists('myjsonfile.json', function(exists) {
if (exists) {
console.log("yes file exists");
fs.readFile('myjsonfile.json', function readFileCallback(err, data) {
if (err) {
console.log(err);
} else {
obj = JSON.parse(data);
for (i = 0; i < 5; i++) {
obj.table.push({
id: i,
square: i * i
});
}
let json = JSON.stringify(obj);
fs.writeFile('myjsonfile.json', json);
}
});
} else {
console.log("file not exists");
for (i = 0; i < 5; i++) {
obj.table.push({
id: i,
square: i * i
});
}
let json = JSON.stringify(obj);
fs.writeFile('myjsonfile.json', json);
}
});
If this JSON file won't become too big over time, you should try:
Create a JavaScript object with the table array in it
var obj = {
table: []
};
Add some data to it, for example:
obj.table.push({id: 1, square:2});
Convert it from an object to a string with JSON.stringify
var json = JSON.stringify(obj);
Use fs to write the file to disk
var fs = require('fs');
fs.writeFile('myjsonfile.json', json, 'utf8', callback);
If you want to append it, read the JSON file and convert it back to an object
fs.readFile('myjsonfile.json', 'utf8', function readFileCallback(err, data){
if (err){
console.log(err);
} else {
obj = JSON.parse(data); //now it an object
obj.table.push({id: 2, square:3}); //add some data
json = JSON.stringify(obj); //convert it back to json
fs.writeFile('myjsonfile.json', json, 'utf8', callback); // write it back
}});
This will work for data that is up to 100 MB effectively. Over this limit, you should use a database engine.
UPDATE:
Create a function which returns the current date (year+month+day) as a string. Create the file named this string + .json. the fs module has a function which can check for file existence named fs.stat(path, callback).
With this, you can check if the file exists. If it exists, use the read function if it's not, use the create function. Use the date string as the path cuz the file will be named as the today date + .json. the callback will contain a stats object which will be null if the file does not exist.
Please try the following program. You might be expecting this output.
var fs = require('fs');
var data = {}
data.table = []
for (i=0; i <26 ; i++){
var obj = {
id: i,
square: i * i
}
data.table.push(obj)
}
fs.writeFile ("input.json", JSON.stringify(data), function(err) {
if (err) throw err;
console.log('complete');
}
);
Save this program in a javascript file, say, square.js.
Then run the program from command prompt using the command node square.js
What it does is, simply overwriting the existing file with new set of data, every time you execute the command.
Happy Coding.
try
var fs = require("fs");
var sampleObject = { your data };
fs.writeFile("./object.json", JSON.stringify(sampleObject, null, 4), (err) => {
if (err) { console.error(err); return; };
console.log("File has been created");
});
For synchronous approach
const fs = require('fs')
fs.writeFileSync('file.json', JSON.stringify(jsonVariable));
you should read the file, every time you want to add a new property to the json, and then add the the new properties
var fs = require('fs');
fs.readFile('data.json',function(err,content){
if(err) throw err;
var parseJson = JSON.parse(content);
for (i=0; i <11 ; i++){
parseJson.table.push({id:i, square:i*i})
}
fs.writeFile('data.json',JSON.stringify(parseJson),function(err){
if(err) throw err;
})
})
Above example is also correct, but i provide simple example:
var fs = require("fs");
var sampleObject = {
name: 'pankaj',
member: 'stack',
type: {
x: 11,
y: 22
}
};
fs.writeFile("./object.json", JSON.stringify(sampleObject, null, 4), (err) => {
if (err) {
console.error(err);
return;
};
console.log("File has been created");
});
For formatting jsonfile gives spaces option which you can pass as a parameter:
jsonfile.writeFile(file, obj, {spaces: 2}, function (err) {
console.error(err);
})
Or use jsonfile.spaces = 4. Read details here.
I would not suggest writing to file each time in the loop, instead construct the JSON object in the loop and write to file outside the loop.
var jsonfile = require('jsonfile');
var obj={
'table':[]
};
for (i=0; i <11 ; i++){
obj.table.push({"id":i,"square":i*i});
}
jsonfile.writeFile('loop.json', obj, {spaces:2}, function(err){
console.log(err);
});
I agree with above answers, Here is a complete read and write sample for anyone who needs it.
router.post('/', function(req, res, next) {
console.log(req.body);
var id = Math.floor((Math.random()*100)+1);
var tital = req.body.title;
var description = req.body.description;
var mynotes = {"Id": id, "Title":tital, "Description": description};
fs.readFile('db.json','utf8', function(err,data){
var obj = JSON.parse(data);
obj.push(mynotes);
var strNotes = JSON.stringify(obj);
fs.writeFile('db.json',strNotes, function(err){
if(err) return console.log(err);
console.log('Note added');
});
})
});
Promise based solution [Javascript (ES6) + Node.js (V10 or above)]
Write to the File:
const fsPromises = require('fs').promises;
fsPromises.writeFile('myFile.json', JSON.stringify({ name: "Sridhar", salary: 1234 }))
.then( () => { console.log('JSON saved'); })
.catch(er => { console.log(er);});
Append to the File:
const fsPromises = require('fs').promises;
fsPromises.readFile('myFile.json', 'utf8')
.then(data => {
let json = JSON.parse(data);
json.myArr.push({name: "Krishnan", salary: 5678});
fsPromises.writeFile('myFile.json', JSON.stringify(json))
.then( () => { console.log('Append Success'); })
.catch(err => { console.log("Append Failed: " + err);});
})
.catch(err => { console.log("Read Error: " +err);});
If your project supports Javascript ES8 then you could use asyn/await instead of native promise.

NodeJS - Mongoose, subdoc object has no method .id() or .create()

I am trying to insert a subdocument using .create() and also query said document using .id(). I've been following the guide here
I am getting the error: object has no method 'id()' or 'create()'
The following is my code:
/db/schemas/AnnouncementsSchema.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var postSchema = new Schema({
title: String,
dateCreated: String,
dateEdited: { type: Date, default: Date.now() },
summary: String,
body: String
});
var announcementsSchema= new Schema({
categoryName: String,
posts: [postSchema]
});
announcementsSchema.methods.Update = function (callback) {
console.log('Updating object: ' + this);
this.save(function (err, object) {
callback(err, object);
});
}
var announcements = mongoose.model('announcements', announcementsSchema);
var post = mongoose.model('post', postSchema);
module.exports = {
announcements: announcements,
post: post
};
/routes/Announcements.js
var mongoose = require('mongoose');
var announcementsSchema = require('../../db/schemas/AnnouncementsSchema.js');
exports.InsertPost = function (req, res) {
var announcements = announcementsSchema.announcements;
var post = announcementsSchema.post;
var categoryToEdit = req.body.categoryToEdit;
var newPost = req.body.newPost;
announcements.GetById(categoryToEdit._id, function (err, announcment) {
var postToAdd = new post(newPost);
announcment.posts.create(postToAdd);
announcment.Update(function (err, object) {
res.send({ err: err, data: object});
});
});
}
I have the .save method wrapped so I can add extra functionality if needed. I crashes when it calls .create(). The same is true if I am trying to remove a post as well. Here is the code for that:
exports.DeletePost = function (req, res) {
var announcements = announcementsSchema.announcements;
var categoryId = req.body.categoryId;
var postId = req.body.postId;
announcements.findById(categoryId, function (err, object) {
var postToDelete = object.posts.id(postId);
console.log(postToDelete);
res.end();
});
}
Either way they both crash and google is pretty slim on answers. Most people have given a of different ways to expose the schemas and models, and what I have above is pretty much a sum of what they suggested. Any ideas? Thanks!
I found the answer after toying with this forever. It was simple. The order in which you declare your schema matters. So I had to declare my subdocument schema before I declare my parent schema. Such as:
var announcementsSchema= new Schema({
categoryName: String,
posts: [postSchema]
});
var postSchema = new Schema({
title: String,
dateCreated: String,
dateEdited: { type: Date, default: Date.now() },
summary: String,
body: String
});
This worked! I am now able to keep all the rest of the code the same, but now the methods exist!
Even if I recently picked up Express.js, I will do my best in trying to provide a useful answer. Hope it helps!
If you want to access the id of a particular post, it is stored in the ._id property, not id. Moreover, I believe that you first have to loop over object.posts since it is an array of posts:
exports.DeletePost = function (req, res) {
var announcements = announcementsSchema.announcements;
var announcementId = req.body.announcementId;
var postId = req.body.postId; // This is the _id property of an element contained within the posts array
var postToDelete = {};
announcements.findById(announcementId, function (err, object) {
// Get the posts array
var posts = object.posts;
// Loop over it until you find the post with the id that you stored in postId
for (var i = 0; i < posts.length; i ++) {
if (posts[i]._id == postId) {
postToDelete = posts[i];
}
}
console.log(postToDelete);
res.end();
});
}
As for your InsertPost function, you should also take into account the fact that posts is an array. Hence, you could simply push the new post into that array and save it accordingly:
exports.InsertPost = function (req, res) {
var announcements = announcementsSchema.announcements;
var post = announcementsSchema.post;
var announcementId = req.body.announcementId;
var newPost = req.body.newPost;
announcements.findById(announcementId, function (err, announcment) {
var postToAdd = new post(newPost);
announcment.posts.push(postToAdd);
announcment.save(function(err) {
if (err) {
res.send(500, { error: err.stack });
}
console.log('Success');
res.end();
});
});
}

Categories