Function not returning anything in nodejs - node.js

I am creating a web app's backend , where different posts are stored and their categories are also stored. Since each category has its own properties (like description , color etc. ) , I've created a new category schema and storing the category reference in the article.
Here's my post route:
Code_1
Code_2
// CREATE ROUTE : adding New Article
app.post("/addnew", upload.single('image'), function(req,res){
//get data from form and add to news array
var title = req.body.title;
var image = req.body.image
if (req.file){
var imgURL = req.file.path;
}
var description = req.body.description;
var category = req.body.category;
var tag = req.body.tag;
// Handling the category entered by user
function checkCategory(name , color, totalArticles, desc){Category.find({name: category}, (err, foundCategory) => {
if(err){
console.log(err)
} else {
console.log("found category in starting of checkCategory function : " , foundCategory)
if (foundCategory[0]){
console.log("Category" + foundCategory + "already exists...")
return foundCategory
} else {
// var name = req.body.name
// var color = req.body.color
// var totalArticles = req.body.totalArticles
// var desc = req.body.desc
var category = {name: name , color : color , totalArticles: totalArticles || 0 , desc : desc }
Category.create(category, (err, newCategory) => {
if (err){
console.log(err)
} else {
console.log("New category Created : " , newCategory)
// category = newCategory
return newCategory
}
})
}
}
})
}
console.log("??????????????? category returned", category)
var nyaArticle= {title: title, imgURL: imgURL, description: description};
// create a new Article and save to db
Article.create(nyaArticle,function(err,newArticle){
if(err){
console.log(err);
} else {
// redirect back to main page
console.log("new article created")
console.log(newArticle)
category = checkCategory(req.body.name, req.body.color, req.body.totalArticles, req.body.desc)
console.log("checkCategory Returned :::::" , category)
newArticle.category.push(category)
newArticle.save()
res.redirect("/");
}
})
The function checkCategory checks if the category already exists or else it will create a new one .
But according to these logs , my function is not returning the category created , however the category is successfully created in DB and also can be seen in Logs
Articles App has started on port 3000
DB Connected...: cluster0-shard-00-00-ktzf1.mongodb.net
??????????????? category returned undefined
new article created
{
category: [],
hits: 0,
tag: [],
comments: [],
_id: 60be0fe92a8b88a8fcea71dc,
title: 'TESTING',
description: 'TESTING',
created: 2021-06-07T12:24:09.563Z,
__v: 0
}
checkCategory Returned ::::: undefined
found category in starting of checkCategory function : []
New category Created : {
totalArticles: 444,
_id: 60be0fea2a8b88a8fcea71dd,
name: 'TESTING',
color: 'RED ALERT',
desc: 'THiS TESTING',
__v: 0
}
due to this null is getting stored in my category in
DB
Am I using the right approach or should I follow some other approach, any help is much welcomed.
The categorySchema looks like this :
var categorySchema = new mongoose.Schema({ name: String, color: String, totalArticles: { type:Number, default: 0 }, desc : String });
ArticleSchema:
var newSchema = new mongoose.Schema({
title: String,
imgURL: String, //{type: String, default: "https://source.unsplash.com/1600x1080/?news"},
description: String,
// category: String,
category: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Category"
}
],
hits : {
type: Number ,
default : 0
},
tag: [
{type: String}
],
created: {type: Date, default: Date.now},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});

You are assigning var category inside the callback function returned from your checkCategory, and that var is only available inside that callback.
Besides, you code have several other problems, like Category.find({name: category}) which will never return anything. (it should be {name:name}).
In general, you'll be much better off using async\await, (coupled with a try\catch, if you like):
async function checkCategory(name, color, totalArticles, desc) {
try {
let category = await Category.findOne({ name });
if (category) {
console.log(`Category ${category.name} already exists...`);
return category;
}
else {
let newCategory = await Category.create({ name: name, color: color, totalArticles: totalArticles || 0, desc: desc });
console.log("New category Created : ", newCategory);
return newCategory;
}
} catch (error) {
console.log(err)
}
}
And in your router function:
app.post("/addnew", upload.single('image'), async function(req,res){
let {name, color, totalArticles, desc} = req.body;
let category = await checkCategory(name, color, totalArticles, desc);
let newArticle = await Article.create({ title: title, imgURL: imgURL, description: description, category: [category] });
res.redirect("/");
}

Related

MONGODB store value in variable to use later

i have a code that inserts information from a 3rd party API every 24hours the api information is ID, Name, Status, Position, Score the only information that can get updated if there is any change are Name, Status, Position, Score, ID will always be the same.
I'm trying to show information based on if there is any change when new data is inserted to the database for example
08/14/2022 ------------- 08/15/2022
Name: yandr1 ========== NO CHANGES
position 1 ========== NO CHANGES
id 123 ========== NO CHANGES
score 100 ========== CHANGES TO: 200 ( POINTS GAINED 100 )
based on the new data inserted to MongoDB Database Score changed from 100 to 200, how can i show on the website the OLD SCORE AND POINTS GAINED? Position, Name,old score, POINTS GAINED
CODE TO INSERT DATA INTO DB FROM API
//POST DAILY PLAYERS DATA//
cron.schedule('56 23 * * *', async () => {
const postSchema = new mongoose.Schema({
id: {
type: Number,
required: true
},
name: {
type: String,
required: true
},
status: {
type: String,
required: false
},
});
const Post = mongoose.model('players', postSchema);
async function getPosts() {
const getPlayers = await fetch("http://localhost:3008/api/players");
const response = await getPlayers.json();
for (let i = 0; i < response.players.length; i++) {
const post = new Post({
id: response.players[i]['id'],
name: response.players[i]['name'],
status: response.players[i]['status'],
});
post.save();
}
}
console.log("Table submitted successfully")
await getPosts();
});
//POST DAILY HIGHSCORE DATA//
cron.schedule('55 23 * * *', async () => {
const postSchema = new mongoose.Schema({
position: {
type: Number,
required: false
},
id: {
type: Number,
required: true
},
score: {
type: Number,
required: false
},
});
const Post = mongoose.model('highscores', postSchema);
async function getPosts() {
const getHighscore = await fetch("http://localhost:3008/api/highscore/players");
const response = await getHighscore.json();
for (let i = 0; i < response.players.length; i++) {
const post = new Post({
position: response.players[i]['position'],
id: response.players[i]['id'],
score: response.players[i]['score'],
});
post.save();
}
}
console.log("Table submitted successfully")
await getPosts();
});
router.get('/export', async function(req, res, next) {
let data
try {
data = await Promise.all([
Posts.list(),
Events.list(),
Messages.list(),
Users.list()
]);
// at this point, data is an array. data[0] = Posts.list result, data[1] = Events.list result etc..
res.status(200).json(data)
} catch (e) {
res.status(500).send('error');
}
});
Hey Yandry try this code-
async function getPosts() {
const getPlayers = await fetch("http://localhost:3008/api/players");
const response = await getPlayers.json();
for( let i = 0;i < response.players.length; i++){
id= response.players[i]['id'];
name= response.players[i]['name'];
status= response.players[i]['status'];
const updateScore = await findOneAndUpdate({id:id},{$set:{name:name,status:status}})
console.log("Updated Score",updateScore)
}
}
Please, try this code, hope you will get solution, if you still facing issue just lemme know, i will help you more.
Thank

POST array of objects using req.body parser

I am trying to post a simple request which includes array of objects. I have created a model and passing the data as per the model.
I am having trouble accessing body parameters as it contains array of data.
I am able to store line item data by req.body.tasks[0]
which is not a standrad way of storing details in mongodb.
I am looking for a standrad way of storing array of data in mongodb
Controller:
let createBug = (req, res) => {
console.log(req.body.tasks[0].subtask[0].description)
for (var key in req.body) {
if (req.body.hasOwnProperty(key)) {
item = req.body[key];
console.log(item);
}
}
const createBug = new listModel({
title: req.body.title,
tasks: [{
title: req.body.tasks[0].title,
description: req.body.tasks[0].description,
subtask: [{
description: req.body.tasks[0].subtask[0].description
}]
}]
}).save((error, data) => {
if (data) {
let apiResponse = response.generate(false, null, 201, data);
res.status(201).send(apiResponse);
} else {
let apiResponse = response.generate(true, error, 404, null);
res.status(404).send(apiResponse);
}
});
};
body:
{
"title":"sample title",
"tasks":[{
"title": "task 1",
"description":"task1 description",
"subtask":[{
"description":"task3 description"
}]
}]
}
Model:
const mongoose = require("mongoose");
const mySchema = mongoose.Schema;
let subtask = new mySchema({
description: String
})
let taskdata = new mySchema({
title: String,
description: String,
subtask: [subtask]
});
let listSchema = new mySchema({
title: {
type: String,
require: true,
},
tasks: [taskdata],
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: "users",
}
});
module.exports = mongoose.model("list", listSchema);
I think you're overcomplicating things here a little bit. The request body exactly matches the model definitions, so you can simply pass the req.body object to your mongoose model:
const createBug = new listModel(req.body).save((error, data) => { ... }

How to get the array of object instead of just _id in Mongoose

I am very new to mongoose.
I am currently building a backend using Node.js, express.js, GraphQL, and mongoose.
I have a Drink schema and DrinkType Schema. I defined DrinkType schema as "alcohol", "juice", "tea". And I have added many drinks and each drink has DrinkType reference. Then, I would like to reference all the drinks from DrinkType.
This is the schema for drinkType
const drinkTypeSchema = new Schema({
name: {
type: String,
required: true,
},
createdDrinks: [
{
type: Schema.Types.ObjectId,
ref: 'Drink',
},
],
Here is the schema for drink
const drinkSchema = new Schema({
name: {
type: String,
required: true,
},
drinkType: {
type: Schema.Types.ObjectId,
ref: 'DrinkType',
},
})
This is the drink resolver. Whenever a new drink is created, I am pushing it to drinkType.
try {
const result = await drink.save()
createdDrink = transformDrink(result)
const drinkType = await DrinkType.findById(args.addDrinkInput.drinkTypeId)
if (!drinkType) {
throw new Error('DrinkType not found.')
}
drinkType.createdDrinks.push(drink)
await drinkType.save()
const drinkLoader = new DataLoader(drinkIds => {
return drinks(drinkIds)
})
const drinks = async drinkIds => {
try {
const drinks = await Drink.find({ _id: { $in: drinkIds } })
return drinks.map(drink => {
return transformDrink(drink)
})
} catch (err) {
throw err
}
}
const transformDrink = drink => {
return {
...drink._doc,
_id: drink.id,
drinkType: drinkType.bind(this, drink.drinkType),
}
}
const drinkType = async drinkTypeId => {
try {
const drinkType = await drinkTypeLoader.load(drinkTypeId.toString())
return {
...drinkType._doc,
_id: drinkType.id,
createdDrinks: () => drinkLoader.loadMany(drinkType._doc.createdDrinks),
}
I want this createdDrinks part to return the array of drink objects, but it is only returning the array of _ids.
I have been reading the mongoose documentation and it seems that using ObjectId is the correct way. Would you mind helping me out?
Thank you in advance.

Refactoring several mongoose models to similar collections

I have several collections that have the same documents type, except for the language.
Let's say imagesES, imagesEN, imagesFR, and so on....
I just thought about definig just one schema, but also one model that get the proper collection with a parameter:
var mongoose = require('mongoose')
var Schema = mongoose.Schema
let authorSchema = require('./Authors').authorSchema
const imageSchema = new Schema({
authors: [authorSchema],
status: Number, // published (1), unpublished (0)
created: { type: Date, default: Date.now },
lastUpdated: { type: Date, default: Date.now },
license: {
type: String,
enum: ['Creative Commons BY-NC-SA'], //just one license right now
default: 'Creative Commons BY-NC-SA'
},
downloads: {
type: Number,
default: 0
},
tags: [String]
})
module.exports = locale => {
return mongoose.model('Image', imageSchema, `image${locale}`)
}
However in the controller I should require the model inside the controller (when I know the locale):
getImageById: (req, res) => {
const id = req.swagger.params.id.value
const locale = req.swagger.params.locale.value
const Images = require('../models/Images')(locale)
Images.findOne({_id: id}).lean().exec( (err, image) => {
I'm not sure if this is the proper way as each request I get I have to require the model module (syncronously) or should I require all the different models previous to the use in the function.
const locales = ['es', 'en', 'fr']
const Images = []
locales.map(locale=>Images[locale] = require('../models/Images')(locale))
getImageById: (req, res) => {
const id = req.swagger.params.id.value
const locale = req.swagger.params.locale.value
Images[locale].findOne({_id: id}).lean().exec( (err, image) => {
Finally this is how I resolved it. Where it says Pictograms, could be Images as in the question
const setPictogramModel = require('../models/Pictograms')
const languages = [
'ar',
'bg',
'en',
'es',
'pl',
'ro',
'ru',
'zh'
]
const Pictograms = languages.reduce((dict, language)=> {
dict[language]= setPictogramModel(language)
return dict
}, {})
module.exports = {
getPictogramById: (req, res) => {
const id = req.swagger.params.idPictogram.value
const locale = req.swagger.params.locale.value
// Use lean to get a plain JS object to modify it, instead of a full model instance
Pictograms[locale].findOne({id_image: id}).exec( (err, pictogram) => {
if(err) {
return res.status(500).json({
message: 'Error getting pictograms. See error field for detail',
error: err
})
}
if(!pictogram) {
return res.status(404).json( {
message: `Error getting pictogram with id ${id}`,
err
})
}
return res.json(pictogram)
})
},

Populate with inherited document in Mongoose

I am trying to create a database schema for the following model:
I am not sure what the better way to represent this in a MongoDb would be, but since I am using Mongoose and there is a plugin for inheritance, I am trying the following:
var mongoose = require('mongoose')
, extend = require('mongoose-schema-extend')
, Schema = mongoose.Schema
, ObjectId = mongoose.Schema.Types.ObjectId
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
//Mashup and Item are bound (itemSchema is a sub-doc)
var itemSchema = new Schema({
pos: { top: Number, left: Number }
, size: { width: Number, height: Number }
, component: { type: ObjectId, ref: 'Component' }
})
var mashupSchema = new Schema({
name: String
, desc: String
, size: { width: Number, height: Number }
, items: [itemSchema]
})
var componentSchema = new Schema({
name: String
, desc: String
}, { discriminatorKey : '_type' })
var imageComponentSchema = componentSchema.extend({
url: String
})
var textComponentSchema = componentSchema.extend({
text: String
})
var htmlComponentSchema = componentSchema.extend({
html: String
})
var webComponentSchema = componentSchema.extend({
page: { type: ObjectId, ref: 'Page' }
, selector: { type: ObjectId, ref: 'Selector' }
})
var pageSchema = new Schema({
name: String
, desc: String
, url: String
, active: { type: Boolean, default: false }
, webComponents: [{ type: ObjectId, ref: 'WebComponent' }]
})
var selectorSchema = new Schema({
desc: String
, url: String
, cssPath: String
})
///MODELS
var Mashup = db.model("Mashup", mashupSchema)
var Component = db.model("Component", componentSchema)
var ImageComponent = db.model("ImageComponent", imageComponentSchema)
var TextComponent = db.model("TextComponent", textComponentSchema)
var HtmlComponent = db.model("HtmlComponent", htmlComponentSchema)
var WebComponent = db.model("WebComponent", webComponentSchema)
var Page = db.model("Page", pageSchema)
var Selector = db.model("Selector", selectorSchema)
//CREATE
//a new empty mashup
//var aMashup = new Mashup({ name: "Test" });
Mashup.create({ name: "Test" }, function (err, mashup) {
if (err) return
console.log("Saved: empty mashup")
//mashup saved, create a webComponent
var aWebComponent = new WebComponent({ name: "Map", desc: "A map" })
//create a page
var aPage = new Page({ name: "Maps", desc: "Google Maps", url: "http://maps.google.com" })
aPage.webComponents.push(aWebComponent)
aWebComponent.page = aPage
//create a selector
var aSelector = new Selector({desc: "Just the map", url: "maps.google.com", cssPath: "#map" })
aWebComponent.selector = aSelector
//save the component
aWebComponent.save(function(err) {
if (err) return
console.log("Saved: WebComponent")
aPage.save(function(err) {
if (err) return
console.log("Saved: the Page")
aSelector.save(function(err) {
if (err) return
console.log("Saved: the Selector")
//finally add the item with the new component
var item = { pos: { top:6, left:10 }, size: { width:100, height:100}, component: aWebComponent }
mashup.items.push(item)
mashup.save(function (err) {
if (err) return
console.log("Saved: mashup with item (WebComponent with Page and Selector)")
//POPULATE
Mashup
.find({})
.populate("items.component")
.exec(function (err, mashup) {
if (err) console.log(err)
console.log(mashup);
})
})
})
})
})
})
});
This is a use case scenario, where a user creates a Mashup and then adds a new Item to it by creating a new WebComponent. I need that Item class because each different mashup should be able to have "instances" (i.e. the Items) of existing Components.
Now, I am new to Mongoose and I am sure things could be done differently. Any suggestion here is welcome. However, when I try to query the Mashups populating the results, the output I get is:
Saved: empty mashup
Saved: WebComponent
Saved: the Page
Saved: the Selector
Saved: mashup with item (WebComponent with Page and Selector)
[ { __v: 1,
_id: 520a8aae3c1052f723000002,
name: 'Test',
items:
[ { component: null,
_id: 520a8aaf3c1052f723000006,
size: [Object],
pos: [Object] } ],
size: {} } ]
component should be populated but it is not. I guess this is because it expects a Componentwhile it gets a WebComponent. How do I fix this? Should I stop trying with inheritance? What other ways are there to create a DB schema for this model?
Doh.. changing
var componentSchema = new Schema({
name: String
, desc: String
}, { discriminatorKey : '_type' })
to
var componentSchema = new Schema({
name: String
, desc: String
}, { collection : 'components', discriminatorKey : '_type' })
Fixes the issue. Not sure why.

Resources