Node.js, Sequelize, cannot convert undefined or null to object - javascript

I'm working on an API and have a special problem. When a make a GET request, i received my JSON Data but the server crash with an error :
for (const key of Object.keys(this.constructor._attributeManipulation)) {
TypeError: Cannot convert undefined or null to object
at Function.keys (<anonymous>)
at Timeout._onTimeout (/Users/quentin/O'Clock/motogpapi/node_modules/sequelize/lib/model.js:83:34)
at listOnTimeout (node:internal/timers:564:17)
at process.processTimers (node:internal/timers:507:7)
I can't undersant origin of this crash. you can find below the code. Is it possible this problem due to as wrong data into db ?
Model team.js:
const { DataTypes, Model } = require("sequelize");
const sequelize = require("../database/client");
class Teams extends Model {}
Teams.init({
name: {
type: DataTypes.STRING,
allowNull: false
},
constructorId: {
type: DataTypes.INTEGER,
allowNull: false
},
isOfficial: {
type: DataTypes.BOOLEAN,
allowNull: false
},
championshipId: {
type: DataTypes.INTEGER,
allowNull: false
},
}, {
sequelize,
tableName: "team"
});
module.exports = Teams;
Model Constructor.js
const { DataTypes, Model } = require("sequelize");
const sequelize = require("../database/client");
class Constructors extends Model {}
Constructors.init({
name: {
type: DataTypes.STRING,
allowNull: false
},
model: {
type: DataTypes.STRING,
allowNull: false
},
engine: {
type: DataTypes.STRING,
allowNull: false
},
}, {
sequelize,
tableName: "constructor"
});
module.exports = Constructors;
Model Index.js i used for associations
const Teams = require("./teams");
const Championships = require("./championships");
const Constructors = require("./constructors");
Constructors.hasMany(Teams, {
foreignKey: "constructorId",
as: "teamsList"
});
Teams.belongsTo(Constructors, {
foreignKey: "constructorId",
as: "constructor"
});
Championships.hasMany(Teams, {
foreignKey: "championshipId",
as: "teamsList"
});
Teams.belongsTo(Championships, {
foreignKey: "championshipId",
as: "championship"
});
module.exports = {
Teams,
Championships,
Constructors
};
The Controller :
const { Teams } = require("../models");
const teamsController = {
async getAllTeams(_, response) {
try {
const teamsList = await Teams.findAll({
include: ["constructor", "championship"]
});
response.json(teamsList);
} catch (error) {
console.log(error);
}
}
};
module.exports = teamsController;
And database/client.js
require("dotenv").config();
const { Sequelize } = require("sequelize");
const sequelize = new Sequelize(process.env.PG_URL, {
define: {
underscored: true
}
});
(async () => {
try {
await sequelize.authenticate();
console.log("Connection has been established successfully.");
} catch (error) {
console.error("Unable to connect to the database:", error);
}
})();
module.exports = sequelize;

Related

Nested schema with map field is not working with mongoose and node js

I’m pretty new to using Mongoose and can’t seem to find a fix. I have two schema’s; postSchema, commentSchema. The first one is for a post and the second is for comments that are stored within the post. Both schema’s have a map field to store likes. The post likes field’s setter and getter work when I try to update but when I try to do the same for the comments it gives me an error that the set or get is not a function. When I check if the likes are an instance of a map, the post likes will return true, while the comments like will return false. If anyone could help or direct me in the right direction it would be greatly appreciated.
Here is the code that I'm working with. When I create a comment to add to a post, the comment.likes checks as a Map. After I update the post I make a call to get all the post's and I rechecked that the comment.likes is a Map, but now it turns out false.
import mongoose from 'mongoose';
const postSchema = mongoose.Schema(
{
userId: {
type: String,
required: true,
},
userName: {
type: String,
required: true,
},
picturePath: {
type: String,
default: '',
},
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
likes: {
type: Map,
of: Boolean,
default: new Map(),
},
comments: {
type: Array,
default: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }],
},
},
{ timestamps: true }
);
const Post = mongoose.model('Post', postSchema);
export default Post;
import mongoose from 'mongoose';
const commentSchema = mongoose.Schema(
{
postId: {
type: String,
required: true,
},
userId: {
type: String,
required: true,
},
userName: {
type: String,
required: true,
},
picturePath: {
type: String,
default: '',
},
description: {
type: String,
required: true,
},
likes: {
type: Map,
of: Boolean,
default: new Map(),
},
},
{ timestamps: true }
);
const Comment = mongoose.model('Comment', commentSchema);
export default Comment;
export const addComment = async (req, res) => {
try {
const { id } = req.params;
const { userId, picturePath, description } = req.body;
const user = await User.findById(userId);
const newComment = new Comment({
id,
userId,
userName: user.userName,
picturePath,
//likes: {},
description,
});
newComment.set('likes', new Map());
console.log(newComment.likes instanceof Map);
const upDatedPost = await Post.findByIdAndUpdate(
id,
{ $push: { comments: newComment } },
{ new: true }
);
const allPost = await Post.find();
console.log(allPost[0].comments[2].likes instanceof Map);
res.status(200).json(allPost);
} catch (err) {
console.log('err');
res.status(404).json({ message: err.message });
}
};
This works for the post.likes.
export const likePost = async (req, res) => {
try {
const { id } = req.params;
const { userId } = req.body;
const post = await Post.findById(id);
const isLiked = post.likes.get(userId);
if (isLiked) {
post.likes.delete(userId);
} else {
post.likes.set(userId, true);
}
const upDatedPost = await Post.findByIdAndUpdate(
id,
{ likes: post.likes },
{ new: true }
);
res.status(200).json(upDatedPost);
} catch (err) {
res.status(404).json({ message: err.message });
}
};
This doesn’t work. When I check if element.likes is an instanceOf Map it gives back false, but for post.likes it returns true. Updated with the console.log's.
export const likeComment = async (req, res) => {
try {
const { id } = req.params;
const { postId, userId } = req.body;
let post = await Post.findById(postId);
let comments = post.comments;
console.log('comments: ', comments);
console.log('likes: ', comments[0].likes);
console.log(
'Is likes an instanceof Map: ',
post.comments[0].likes instanceof Map
);
//comments[0].likes.set(userId, true);
//post.comments[0].set('likes', new Map());
//console.log(comments[6].likes);
// comments.forEach((element) => {
// if (element._id.toString() === id) {
// element.likes.set(userId, true);
// }
// });
res.status(200).json(post);
} catch (err) {
res.status(404).json({ message: err.message });
}
};
Here is the output fro the console.log's.
comments: [
{
userId: '63dc0274bd8c03b1e417cfc4',
userName: 'dummyUserThree',
picturePath: '',
description: 'Likes still not working',
_id: new ObjectId("63e13f26603a052fc8f16b09"),
likes: {}
}
]
likes: {}
Is likes an instanceof Map: false

Why do I get `no such table` even though I created the model?

I don't understand why I get Error: SQLITE_ERROR: no such table: cities even though I created the model with Sequelize. I followed the same code that worked fine last time.
models/cities.js:
const { Sequelize, DataTypes } = require('sequelize');
const db = new Sequelize({
dialect: 'sqlite',
storage: './database.sqlite',
});
const Cities = db.define('cities', {
userId: {
type: DataTypes.STRING,
unique: true,
primaryKey: true,
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
// ...
busStationsBuilt: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
},
});
module.exports = { Cities };
db-init.js (run manually):
const { Sequelize } = require('sequelize');
const db = new Sequelize({
dialect: 'sqlite',
storage: './database.sqlite',
});
require('./models/cities.js');
const force = process.argv.includes('--force') || process.argv.includes('-f');
db.sync({ force }).then(async () => {
console.log('Database synced.');
db.close();
}).catch(console.error);
commands/found.js:
const { Cities } = require('../models/cities.js');
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('found')
.setDescription('Found your city!')
.addStringOption(option =>
option
.setName('name')
.setDescription('The name of your city!')
.setRequired(true)
),
async execute(interaction) {
const name = interaction.options.getString('name');
const cityAlreadyExists = await Cities.findOne({ where: { userId: interaction.user.id } });
if (!cityAlreadyExists) {
try {
const city = await Cities.create({
userId: interaction.user.id,
name: name,
});
const cityEmbed = new EmbedBuilder()
.setColor(0x73a0d0)
.setTitle(city.name)
.setDescription('Here are your city\'s stats:')
.addFields(
{ name: '😄 Happiness:', value: city.happiness },
{ name: '🧍 Population:', value: city.population },
{ name: '💵 Balance:', value: city.balance },
{ name: '🪨 Resources:', value: city.resources },
{ name: '👨‍👩‍👧‍👦 Crowdedness:', value: city.crowdedness },
{ name: '🚗 Traffic:', value: city.traffic },
{ name: '🛢️ Pollution:', value: city.pollution },
);
return interaction.reply({ content: 'Your city has been created!', embeds: [cityEmbed] });
} catch (error) {
await interaction.reply({ content: 'An error occurred while creating your city. Support server: https://discord.gg/XuZNNJbf4U', ephemeral: true });
return console.error(error);
}
} else {
return interaction.reply('Your city already exists!');
}
}
}
I've asked similar questions and everything worked fine then so I'm not sure what went wrong this time. There are no issues/errors when I run db-init.js but I get the error when I run /found.
It looks like you are probably creating multiple databases because the storage path variable is relative to the file where you're creating the Sequelize db:
const db = new Sequelize({
dialect: 'sqlite',
storage: './database.sqlite',
});
I suggest you use an absolute path to your sqlite db file. Check out this answer for some help on getting path info in node.js.

CastError: Cast to [undefined] failed for value "[]" (type string) at path "comments.undefined"

I'm quite new to node and mongoose. I'm trying to do a project using them, but i'm running into an error while trying to populate. The comment is saved to the Comment schema perfectly, but throws an error when i reference it Organization Schema.Please advise me on what i'm doing wrong. Any form of assistance will be appreciated.
// Post route for comment(on the Organization's profile page)
router.post('/comment/:id', ensureAuthenticated,(req, res) =>{
let id = req.params.id;
console.log(mongoose.Types.ObjectId.isValid(id))
const commentObject = new Comment({
sender: 'Fred kimani',
commentBody: req.body.commentBody
})
console.log(commentObject);
commentObject.save((err, result) =>{
if(err){console.log(err)}
else{
Organization.findByIdAndUpdate(id, {$push: {comments: result}}, {upsert: true}, (err, organization) =>{
if(err){console.log(err)}
else{
console.log('======Comments====')
}
})
res.redirect('/users/organizationprofilepage/:id')
}
})
});
//Organization Schema
const mongoose = require('mongoose');
const OrganizationSchema = new mongoose.Schema({
organization_name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
category: {
type: String,
required: true
},
isApproved: {
type: Boolean,
default: false
},
image:{
type:String,
required:true
},
description: {
type: String,
required: true,
},
comments: [{
type: mongoose.Types.ObjectId,
ref: 'Comment'
}],
},
//{ typeKey: '$type' }
);
OrganizationSchema.statics.getOrganizations = async function () {
try {
const organizations = await this.find();
return organizations;
} catch (error) {
throw error;
}
}
//defines the layout of the db schema
const Organization = mongoose.model('0rganization', OrganizationSchema);
module.exports = Organization;
//Comment schema
const mongoose = require('mongoose');
const CommentSchema = mongoose.Schema({
sender: {
type: String,
},
commentBody: {
type: String,
required: false,
},
date: {
type: Date,
default: Date.now
},
})
CommentSchema.statics.getComments= async function () {
try {
const comments = await this.find();
return comments ;
} catch (error) {
throw error;
}
}
const Comment= mongoose.model('Comment', CommentSchema);
module.exports = Comment;
Try to change the comments type to mongoose.Schema.Types.ObjectId:
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment',
},
],
Try to push the new commend _id into the Organization object after its creation, not the whole object:
commentObject.save((err, result) => {
if (err) {
console.log(err);
} else {
Organization.findByIdAndUpdate(
id,
{ $push: { comments: result._id } }, // <- Change this line
{ upsert: true },
(err, organization) => { }
);
...
}
});
If you just updated the schema you will need to make sure all of the comments are following the new form you created, when you save it will attempt to validate them, that is why an updateOne will work but not await save()

Sequelize error using association on n:m related objects

I am using nodeJS, express (4.17.1), sequelize (5.21.4) and mysql (mysql2 v2.1.0) for a current project.
In my database I have three tables Filter, Element and FilterElement. If I query data from database from Filter or Element table separatly I get the result of objects with data. If I want to use "connecting" table FilterElement I get this error {"name":"SequelizeEagerLoadingError"}
EagerLoadingError [SequelizeEagerLoadingError]: filter_element is not
associated to filters_new!
What is wrong with my code?
These are my sequelize objects codes.
Filter.js
const Sequelize = require('sequelize');
const db = require('../config/database');
const Filter = db.define('filters_new', {
Model:{
type: Sequelize.STRING,
primaryKey: true,
allowNull: false
}
},
{
timestamps: false,
freezeTableName: true
}
);
Filter.associate = function(models) {
Filter.belongsToMany(models.Element, {
through: models.FilterElement,
as: 'filter',
foreignKey: 'FilterHousingModel'
});
};
module.exports = Filter;
Element.js
const Sequelize = require('sequelize');
const db = require('../config/database');
const Element = db.define('filter_element', {
idfilter_element:{
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false
},
ElementName:{
type: Sequelize.STRING,
}
},
{
timestamps: false,
freezeTableName: true
}
);
Element.associate = function(models) {
Element.belongsToMany(models.Filter, {
through: models.FilterElement,
as: 'element',
foreignKey: 'FilterElementId'
});
};
module.exports = Element;
FilterElemnt.js
const Sequelize = require('sequelize');
const db = require('../config/database');
const FilterElement = db.define('filters_new', {
idfilter_filterelement:{
type: Sequelize.STRING,
primaryKey: true,
allowNull: false,
autoincrement: true
},
FilterHousingModel: {
type: Sequelize.STRING
},
FilterElementId: {
type: Sequelize.INTEGER
}
},
{
timestamps: false,
freezeTableName: true
}
);
module.exports = FilterElement;
If I call this function, I do get the desired result of data from database.
listFiltersOnly(req, res) {
return filter.findAll()
.then((filters) => {
res.status(200).send(filters);
})
.catch(err => {
console.log(err);
res.status(400).send(err);
});
}
then if I call function list I get the error mentioned up EagerLoadingError
list(req, res) {
return filter.findAll({
include: [{
model: element,
as: 'element'
}],
})
.then((filters) => {
console.log(filters);
res.status(200).send(filters);
})
.catch(err => {
console.log(err);
res.status(400).send(err);
});
}
Looking for some suggjestions where might be the problem?
#RatulSharker I removed the asociation from the model and added it where the models are implemented in the controller and now I do get some results.
Filter.belongsToMany(FilterElement, {
through: FilterFilterElement,
foreignKey: 'FilterHousingModel'
});
FilterElement.belongsToMany(Filter, {
through: FilterFilterElement,
foreignKey: 'FilterElementId'
});
Thank you #Ratul Sharker

NodeJS Sequalize Table1 is not associated to Table2

I have two tables table1 and table2. i want to get relational data. I gone through this URL which is same as the my error but that solution is not work for me
module.exports = function (sequelize, DataTypes) {
var table1 = sequelize.define("table1", {
table1Id: {type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true},
image: {type: DataTypes.STRING},
}, {
timestamps: true,
classMethods: {
associate: function (models) {
table1.belongsTo(models.table2, {
onDelete: "CASCADE",
foreignKey: {
name: "table2Id",
notEmpty: false
}
});
}
}
});
return table1;
};
and another is :
module.exports = function (sequelize, DataTypes) {
var table2 = sequelize.define("table2", {
table2Id: {type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true},
name: {type: DataTypes.STRING},
}, {
timestamps: true,
classMethods: {
associate: function (models) {
table2.hasMany(models.table1, {
onDelete: "CASCADE",
foreignKey: {
name: "table1Id",
notEmpty: false
}
});
}
}
});
return table2;
};
then in controllers:
models.table2.findById(req.params.id, {
include: [{model: models.table1}]
}).then(function (data) {
}).catch(Sequelize.ValidationError, function (err) {
return res.status(422).send(err.errors);
}).catch(function (err) {
console.log(err.message,"err.message")
return res.status(400).send({
message: err.message
});
});
and i got error that Table1 is not associated to Table2
If you are on sequelize >4
The way association are defined is changed.
Instead of defining association as
const Model = sequelize.define('Model',
{ ... },
{ classMethods: { associate: function (model) {...} }
});
They are now defined as
const Model = sequelize.define('Model', { ... });
// Class Method
Model.associate = function (models) { ...associate the models };
This could also justify why it seems to work on one machine and not the other.

Categories