Sequelize model query with [or] not retrieving data - node.js

I have a project that I am working on. I build the database models with sequelize. Not I am running the controller. In one of the methods, I want to pass in a userId into the url as a parameter. With that userId, I want to check and see if any of the records has the passed in userId in the friendedId or frienderId fields within the databse.
I am using the [or] in the filtering to make that query return all records and it currenty returns none.
this is the controller method:
getByUser: (req, res) => {
let user_id = req.params.userId;
Friend.findAll({ where: {[or]: [{ frienderId: user_id }, { friendedId: user_id }]}})
.then((response) => {
console.log(response)
res.status(200).send(response.dataValues)
})
.catch()
},
this is the model:
const seq = require('sequelize');
const { database } = require('../index');
const { User } = require('./User');
const Friend = database.define(
"friend",
{
id: {type: seq.INTEGER, primaryKey: true, autoIncrement: true},
status: {type: seq.STRING, allowNull: false,
validate: {isIn:[['Pending', 'Accepted']], isAlpha: true}
},
favorite: {type: seq.BOOLEAN, allowNull: false, defaultValues: false,
validate: {isIn: [['true', 'false']]}
},
},
{
createdAt: seq.DATE,
updatedAt: seq.DATE,
}
)
Friend.belongsTo(User, {as: 'friender'})
Friend.belongsTo(User, {as: 'friended'})
database.sync()
.then(() => {
console.log('Connected the Friend model to database')
})
.catch((err) => {
console.log('Issue connected the Friend model to the database: ' + JSON.stringify(err))
})
module.exports.Friend = Friend;

Related

Sequelize findAll method not returning entries in the database

I have connected my app to an existing database. The database table currently has 3 entries but, when I query the model using findAll only an empty array is returned. Im not sure if this has something to do with the database already and existing and connecting to it through models. I am also syncing all files in the index file in the models directory.
//Courses Model for sequelize
const Sequelize = require('sequelize');
module.exports = (sequelize) => {
class Courses extends Sequelize.Model{}
Courses.init({
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
title: {
type: Sequelize.STRING,
allowNull: false
},
description: {
type: Sequelize.TEXT,
allowNull: false
},
estimatedTime: {
type: Sequelize.STRING,
},
materialsNeeded: {
type: Sequelize.STRING,
},
createdAt: {
type: Sequelize.DATE,
allowNull: false
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false
},
userId: {
type: Sequelize.INTEGER,
references: { model: 'users', key: 'id' },
onDelete: 'CASCADE',
allowNull: false
}
}, {sequelize, modelName: 'courses'});
Courses.associate = (models) => {
models.courses.belongsTo(models.users, {foreignKey: "userId"});
};
return Courses
}
// Router with findAll query
const router = require('express').Router();
const db = require('../models/');
router.get('/', async(req, res) => {
try {
console.log(await db.courses.findAll());
} catch(err) {
console.error(err);
}
res.json({msg: "None"})
});
module.exports = router;
[This is the courses table currently][1]
[1]: https://i.stack.imgur.com/2KkK6.png
This is javascript level issuse I guess. You can't use await statement like that. Please try this out first.
onst router = require('express').Router();
const db = require('../models/');
router.get('/', async (req, res) => {
try {
const courese = await db.courses.findAll()
console.log(courses)
res.send({ courses })
} catch(err) {
console.error(err);
}
res.json({msg: "None"})
});
module.exports = router;
If the problem remains after running this, check if your config is pointing right database.
For checking whether this is problem.
Change your config to point existing database
Run the code
Change your config to point local database with different schema
Do the sequelize sync
Run the code
By doing so, you can check what is the real problem in your code.

beforeBulkDestroy not finding model property to change

I am trying to use the beforeBulkDestory Sequelize hook on a user delete that will switch the deleted column boolean to true prior to updating the record to add a timestamp for deleted_at. However, when I console.log the function parameter it provides a list of options and not the model object that I can update for the record of focus. Am I approaching this the wrong way? Is this something that should be set using model instances?
API Call:
import db from '../../../models/index';
const User = db.users;
export default (req, res) => {
const {
query: { id },
} = req
console.log(User)
if (req.method === 'DELETE') {
User.destroy({
where: {
id: id
}
}).then(data => {
res.json({
message: 'Account successfully deleted!'
})
})
} else {
const GET = User.findOne({
where: {
id: id
}
});
GET.then(data => {
res.json(data)
})
}
}
Parameter Values (beforeBulkDestroy, afterBulkDestroy):
beforeBulkDestroy
{
where: { id: '5bff3820-3910-44f0-9ec1-e68263c0f61f' },
hooks: true,
individualHooks: false,
force: false,
cascade: false,
restartIdentity: false,
type: 'BULKDELETE',
model: users
}
afterDestroy
{
where: { id: '5bff3820-3910-44f0-9ec1-e68263c0f61f' },
hooks: true,
individualHooks: true,
force: false,
cascade: false,
restartIdentity: false,
type: 'BULKUPDATE',
model: users
}
Model (users.js):
'use strict';
const Sequelize = require('sequelize');
const { Model } = require('sequelize');
const bcrypt = require("bcrypt");
module.exports = (sequelize, DataTypes) => {
class users extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
};
users.init({
id: {
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
primaryKey: true
},
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
password: {
type: DataTypes.STRING
},
email: DataTypes.STRING,
active: {
type: DataTypes.BOOLEAN,
defaultValue: true
},
deleted: {
type: DataTypes.BOOLEAN,
defaultValue: false
}
}, {
hooks: {
beforeDestroy: (user, options) => {
console.log("beforeDestroy")
console.log(user)
console.log(options)
user.deleted = true
}
},
sequelize,
freezeTableName: true,
modelName: 'users',
omitNull: true,
paranoid: true,
underscored: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
deletedAt: 'deleted_at',
hooks: {
beforeCreate: async function(user){
console.log("beforeCreate")
console.log(user)
const salt = await bcrypt.genSalt(12);
user.password = await bcrypt.hash(user.password, salt);
console.log(user.password)
},
beforeBulkDestroy: async function(user){
console.log("beforeBulkDestroy")
console.log(user)
},
afterBulkDestroy: async function(user){
console.log("afterDestroy")
console.log(user)
}
}
});
users.prototype.validPassword = async function(password) {
console.log("validatePassword")
console.log(password)
return await bcrypt.compare(password, this.password);
}
return users;
};
the before/after bulkDestroy hooks only receive the options, not the instances. One way you could do this is defining a before/after Destroy hook:
hooks: {
beforeDestroy: (user, { transaction }) => {
user.update({ deleted: true }, { transaction });
}
}
and calling User.destroy with the individualHooks option:
User.destroy({ where: { id: id }, individualHooks: true });
Be aware that this will load all selected models into memory.
Docs
Note: In your case, since you're only deleting one record by id, it would be better to just user = User.findByPk(id) then user.destroy(). This would always invoke the hooks and it also makes sure the record you want to delete actually exists.
Note 2: Not sure why you need a deleted column, you could just use deletedAt and coerce it into a boolean (with a virtual field if you want to get fancy).

How can users like and unlike each others post using sequelize postgres nodejs?

I am trying to implement that users can like each others post.
Here is my Likes model:
const Likes = db.define("Likes", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
PostId: {
type: Sequelize.INTEGER,
references: {
model: "Post",
key: "id",
},
onUpdate: "cascade",
onDelete: "cascade",
},
userId: {
type: Sequelize.INTEGER,
references: {
model: "User",
key: "id",
},
onUpdate: "cascade",
onDelete: "cascade",
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
Here is my Post Model:
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
title: {
type: Sequelize.STRING,
},
userId: {
type: Sequelize.INTEGER,
},
Here is my Users Model:
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: Sequelize.STRING,
},
and here are my associations:
db.Likes.belongsTo(db.User, { foreignKey: "userId", targetKey: "id" });
db.Likes.belongsTo(db.Post, { foreignKey: "PostId", targetKey: "id" });
db.Post.hasMany(db.Likes, { foreignKey: "PostId", targetKey: "id" });
db.User.hasMany(db.Likes, { foreignKey: "userId", targetKey: "id" });
Here is my post and delete request:
router.post("/:id/likes", async (req, res, next) => {
const { userId } = req;
const PostId = req.params.id;
const post = await Post.findByPk(PostId);
if (!post)
return res
.status(404)
.send({ message: "Post cannot be found or has been removed" });
let like = await Likes.findOne({
where: { [Op.and]: [{ PostId: req.params.id }, { userId:
req.userId }] },
});
if (!like) {
let newLike = await Likes.create({
userId: userId,
PostId: req.params.id,
});
return res.json(newLike);
} else {
await like.destroy();
return res.send();
}
});
I keep getting UnhandledPromiseRejectionWarning: Error: WHERE parameter "userId" has invalid "undefined" value.
In my frontend when i do console.log(user.id) i get the id of the user liking a post and when i do console.log(post.id) i get the id of the post being liked.
UPDATE
in frontend here is how i am send the data to backend:
const likePost = (like) => {
const data = new FormData();
data.append("userId",like.userId);
data.append("PostId",like.PostId)
console.log(like.PostId) // the post id is shown in terminal
console.log(like.userId) // the user id is shown in terminal
console.log(like)
return client.post(`/posts/${like.PostId}/likes`, data);
}
console.log(like) returns this
Object {
"PostId": 489,
"userId": 43,
}
which is the correct id of the post and user liking the post.
in backend here is my post request:
router.post("/:id/likes", async (req, res, next) => {
console.log(req.body); // returns an empty object {}
const PostId = req.params.id;
const post = await Post.findByPk(PostId);
if (!post)
return res
.status(404)
.send({ message: "Post cannot be found or has been removed" });
let like = await Likes.findOne({
where: {
[Op.and]: [
{ PostId: req.params.id },
// { userId: req.body.userId }
],
},
});
if (!like) {
let newLike = await Likes.create({
// userId: req.body.userId,
PostId: req.params.id,
});
return res.json(newLike);
} else {
await like.destroy();
return res.send();
}
});
after doing this i still cannot get the userId in req.body
It seems like you need req.params.userIdin your findOne query, assuming that the userId is passed in the params of the request:
{ userId: req.params.userId }
client.post(/posts/${like.PostId}/likes, { userId: like.userId, PostId:like.PostId })
using this in frontend, i was able to access the req.body in backend, thank you #Anatoly
You can apply this in order to get isLiked true or false
const gender = await db.SubProduct.findAll(userId && {
attributes: {
include: [
[Sequelize.cast(Sequelize.where(Sequelize.col("likes.userId"), userId), "boolean"), "isLiked"]
],
},
include: [
{ model: db.Like, as: "likes", attributes: [], required: false },
],
group: ['SubProduct.id', 'likes.id']
});

NodeJS Sequelize: Association with alias [alias] does not exist on [model]

i'm using NodeJS & Sequelize for a school project and i'm struggling on making associations w/ sequelize work. I tried a couple of things before but nothing that made my day.
Basically the thing is that a user can have several playlists (hasMany).
And a playlist belongs to a user (belongsTo).
My error is:
Association with alias "playlist" does not exist on users
Here are my models:
/* USER MODEL */
const Sequelize = require('sequelize');
const { db } = require('../utils/db');
const User = db.define('users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
userID: {
type: Sequelize.INTEGER,
allowNull: false,
field: 'user_id',
},
firstName: {
type: Sequelize.STRING,
field: 'first_name',
allowNull: false,
},
}, {
underscored: true,
tableName: 'users',
freezeTableName: true, // Model tableName will be the same as the model name
});
module.exports = {
User,
};
/* PLAYLIST MODEL */
const sequelize = require('sequelize');
const { db } = require('../utils/db');
const Playlist = db.define('playlist', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: sequelize.INTEGER,
},
name: {
type: sequelize.STRING,
field: 'name',
allowNull: false,
},
coverUrl: {
type: sequelize.STRING,
field: 'cover_url',
allowNull: true,
},
ownerId: {
type: sequelize.INTEGER,
allowNull: false,
references: {
model: 'users',
key: 'user_id',
},
},
}, {
underscored: true,
tableName: 'playlist',
freezeTableName: true,
});
module.exports = {
Playlist,
};
Here is how i load my models:
const { Credentials } = require('./credentials');
const { User } = require('./users');
const { Playlist } = require('./playlist');
function loadModels() {
User.associate = (models) => {
User.hasMany(models.Playlist, { as: 'playlist' });
};
Playlist.associate = (models) => {
Playlist.belongsTo(models.User, { foreignKey: 'owner_id', as: 'owner' });
};
Credentials.sync({ force: false });
User.sync({ force: false });
Playlist.sync({ force: false });
}
module.exports = {
loadModels,
};
And finally here is my query where i get this error:
const express = require('express');
const { auth } = require('../../middlewares/auth');
const { Playlist } = require('../../models/playlist');
const { User } = require('../../models/users');
const router = express.Router();
router.get('/playlist', [], auth, (req, res) => {
User.findOne({
where: { userID: req.user.user_id }, include: 'playlist',
}).then((r) => {
console.log(r);
});
});
module.exports = router;
I'm trying to get all the playlist that belongs to a user.
I removed all the useless code (jwt check etc..)
So when i'm doing a get request on /playlist I get:
Unhandled rejection Error: Association with alias "playlist" does not exist on users.
I understand the error but don't understand why i get this.
What did I miss, any ideas ?
Thanks,
I finally fixed it by re-make all my models and definitions with migrations.
I had the same problem and the solution was that Sequelize pluralize the models name so in my case "playlist" does not exist on users because Sequelize pluralized my model so I had to put "Playlists" instead.

How to build model with sequelize for belong to many association

This is what I wrote in Country.js (exactly the same as User.js except datatypes) :
module.exports = function(sequelize, DataTypes) {
const Country = sequelize.define('country',
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
code: {
type: DataTypes.INTEGER
},
alpha2: {
type: DataTypes.STRING
},
alpha3: {
type: DataTypes.STRING
},
name_en: {
type: DataTypes.STRING
},
name_fr: {
type: DataTypes.STRING
}
},
{
freezeTableName: true,
timestamps: false
});
Country.associate = ( models ) => {
models.Country.belongsToMany(models.User, {
through: 'country_user',
as: 'user',
foreignKey: 'id_country'
});
};
return Country;
}
This is my query :
router.get('/thisuserCountries', function(req, res, next){
User(db, Sequelize.DataTypes).findOne({
include: [{
model: Country(db, Sequelize.DataTypes),
as: 'countries',
required: false,
attributes: ['id'],
}],
where: {
email: 'jerome.charlat#gmail.com'
}
})
.then(user => {
if(user) {
res.json(user)
}
else {
res.send('User does not exist')
}
})
.catch(err => {
res.send('error: ' + err)
})
})
This is my db.js :
const Sequelize = require('sequelize')
const db = new Sequelize('travel_memories', 'root', '', {
host: 'localhost',
dialect: 'mysql',
port: 3306
})
db
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
const models = {
Country: db.import('../models/Country'),
User: db.import('../models/User'),
CountryUserJoin: db.import('../models/Country_user')
};
Object.keys(models).forEach((modelName) => {
if('associate' in models[modelName]){
models[modelName].associate(models);
}
});
module.exports = db
Postman says : error SequelizeEagerLoadingError: country is not associated to user!
But, I think I should write in the through parameter the model User_country when I associate tables in each model. So i tried to write something like :
Country.associate = ( models ) => {
models.Country.belongsToMany(models.User, {
through: models.Country_user,
as: 'user',
foreignKey: 'id_country'
});
};
And console says when I launch server, before querying anything :
SequelizeAssociationError: country.belongsToMany(user) requires through option, pass either a string or a model.
So I am blocked. I used the example in documentation to write the assocation with models.foo. But in fact models comes from nowhere..
Thanks again for your help !
There's not a lot of documentation about this, but here it says that you should use a through option when querying or selecting belongs-to-many attributes, just like this:
...
User(db, Sequelize.DataTypes).findOne({
include: [{
model: Country(db, Sequelize.DataTypes),
as: 'countries',
required: false,
through: {
attributes: ['id']
}
}],
where: {
email: 'jerome.charlat#gmail.com'
}
})
...

Resources