Sequelize Default Exclude - node.js

I have a table named person, I want a column to be excluded as default,
const Person = sequelize.define('person',{
secretColumn: Sequelize.STRING,
//... and other columns
});
I see that there is a feature called Scope in Sequelize:
http://docs.sequelizejs.com/manual/tutorial/scopes.html
I tried to exclude like this;
const Person = sequelize.define('person',{
secretColumn: Sequelize.STRING,
//... and other columns
}, {
defaultScope: {
exclude: ['secretColumn']
}
});
But that does't work. Is there any other way to exclude a column by default?

I firgured it out. exclude needs to be in attributes part:
const Person = sequelize.define('person',{
secretColumn: Sequelize.STRING,
//... and other columns
}, {
defaultScope: {
attributes: { exclude: ['secretColumn'] }
}
});

Related

how to set order on include aggregate function alias in sequelize?

Below is my code
export async function getMany(page: number, recordsPerPage: number, condition: any = {}, order: any, attributes: string[] = [], other: object = {}) {
try {
let { count, rows }: any = await User.findAndCountAll({
attributes: {
include: [[sequelize.literal('(SELECT SUM(reputation) FROM scores where scores.user_id = User.id)'), 'reputation']],
exclude: attributes,
},
where: condition,
distinct: true,
include: [
{
model: Skill,
as: 'skills',
attributes: ['skill'],
through: { attributes: [] },
},
],
order: order,
offset: page,
limit: recordsPerPage,
...other,
logging: console.log,
});
return { count, rows };
} catch (e) {
return false;
}
}
I want to set order by reputation field which is alias of sum function column. i want my data in highest to lowest reputation.
You can simply replace the order property with the given snippet. Worked for me.
order: [[sequelize.literal('table alias name goes here'), 'DESC']]

How do you exclude and include fields in Sequelize by scope?

const getMe = await UserModel.scope("test").findOne({
where: {
uid: uid,
},
include: [
{
model: GroupModel,
as: "groups",
include: ["product"],
},
],
});
I am trying to manage excluding fields and allowing fields based on scope.
defaultScope: {
attributes: {
exclude: ["id"],
},
},
scopes: {
test: {
atrributes: {
exclude: ["email"],
},
},
},
associations
UserModel.hasMany(GroupModel, { as: "groups" });
Groupmodel.belongsTo(UserModel, {
foreignKey: "userId",
as: "user",
});
GroupModel.belongsTo(ProductModel, {
foreignKey: "productId",
as: "product",
});
As a test I am by default excluding "id", and with the test scope I am excluding "email". I have tried everything from exclude include setting attributes directly in the findOne call. Nothing works.
What is the proper way to exclude certain fields say for "Public" returns, and include all fields for an "Admin scope" of some sort?
If you have defaultScope like this.
defaultScope: {
attributes: {
exclude: ['email']
}
}
When you do find query, it excludes "email" by default and use unscoped to disable the defaultScope.
// This should not return email
UserModel.findOne()
// Admin case: unscoped to disable defaultScope. This should return email.
UserModel.unscoped().findOne()
Alternatively, if you would like to be more explicit, you can have scope named "admin".
{
defaultScope: {
attributes: {
exclude: ['email']
}
},
scopes: {
admin: {} // No special options for admin scope. No exclusion.
}
}
This way when you do find query, it is excluding "email" by default. Then, if you use "admin" scope, it won't exclude anything.
// This should not return email
UserModel.findOne()
// Admin case: This should overwrite the defaultScope.
UserModel.scope('admin').findOne()
.scope(str) function overwrites the defaultScope, so any options in defaultScope is ignored when you use .scope(str).

Nodejs sequelize hasMany issue

I've breaking my head over this sequelize to get the products questions and also to include its answers as well
const ProductQuestions = sequelize.define('product_questions', {
user: {
type: Sequelize.BIGINT
},
product: {
type: Sequelize.BIGINT
},
question: {
type: Sequelize.TEXT
}
});
ProductQuestions.associate = function(models) {
ProductQuestion.hasMany(models.product_answers,{
foreignKey: 'question',
as: 'questionId'
});
}
const ProductAnswer = sequelize.define('product_answers', {
question: {
type: Sequelize.BIGINT,
field: 'questionId'
},
answer: {
type: Sequelize.TEXT
},
user: {
type: Sequelize.BIGINT,
field: 'userId'
}
});
ProductQuestiosn.findAll({include: ['product_answers']});
for some reason when I that, the columns is wrong when the query runs
SELECT
"product_questions".*,
"product_answers"."id" AS "product_answers.id",
"product_answers"."questionId" AS "product_answers.questionId",
"product_answers"."answer" AS "product_answers.answer",
"product_answers"."userId" AS "product_answers.user",
"product_answers"."productQuestionId" AS "product_answers.productQuestionId"
FROM (
SELECT
"product_questions"."id",
"product_questions"."productId" AS "product",
"product_questions"."question",
"product_questions"."userId" AS "user",
FROM
"product_questions" AS "product_questions")
AS "product_questions"
LEFT OUTER JOIN "product_answers" AS "product_answers"
ON "product_questions"."id" = "product_answers"."productQuestionId"
not sure why is
ON "product_questions"."id" = "product_answers"."productQuestionId"
when it should be
ON "product_questions"."id" = "product_answers"."questionId"
thank you for your help
so i figured it out!
so it appears that I have to name my columns properly
for the product_answers table in my postgres database, I had the column questionId but it should be named productQuestionId. I guess it's for naming convention, i can't just name the foreign key the way i want.

Sequelize: how to implement a search based on associated keywords?

I am looking to return all articles from the database associated with one or more keywords, but I am not sure there right way to go about this?
I am using Sequelize 3.x, with node.js 3.7.0.
The data model looks at follows:
const Article = sequelize.define('article', {
...
}
const Keyword = sequelize.define('keyword', {
name: Sequelize.STRING,
lang: Sequelize.STRING
}
const ArticleKeyword = sequelize.define('article_keyword', {
articleId: Sequelize.INTEGER,
keywordId: Sequelize.INTEGER
}
(Article).belongsToMany(
Keyword, { through: ArticleKeyword, as: 'keyword' });
(Keyword).belongsToMany(
Article { through: ArticleKeyword, as: 'article' });
Then the query I tried:
var keywordFilter;
if (req.body.keywords) {
var keywords = req.body.keywords);
if (typeof keywords === 'string') {
keywords = keywords.split(/ *, */);
}
keywordFilter = { name: { $in: keywords } };
}
Article.findAll({
where: {
deleted: false
},
include: [{
model: Keyword,
as: 'keywords',
where: keywordFilter,
attributes: ['name'],
through: {
attributes: []
}
}]
}).then(function(articles) {
...
});
The issue I am finding here is rather than selecting just the articles with the matching keywords it returns all the articles and then simply selects the keywords specified in the query for the results.
Can anyone suggest the right way to go about this?
Hi can you try passing
require:true
in the include block for inner join and check
Ref : https://stackoverflow.com/a/31680398/4583460

Access inner join data from sequelize using include

I am trying to join two tables using Sequelize's include as such:
models.user.findAll({include: {model: models.boardMember, required:true}})
.then(function(board) {
console.log(board);
res.render('contact', { title: 'Kontakt', board: board });
});
My models look like this using the sequelize express example:
User (it doesn't quite feel right having the hasMany here instead of in boardMembers, but I didn't want to have the foreign key field in the users table)
module.exports = function(sequelize, DataTypes) {
var user = sequelize.define('user', {
//lots of normal user fields(username, password, access...
}, {
classMethods: {
associate: function(models) {
user.hasMany(models.boardMember, {
foreignKey: {
allowNull: false
}
});
}
}
});
return user;
};
boardMember
module.exports = function(sequelize, DataTypes) {
var boardMember = sequelize.define('boardMember', {
post: {
type: DataTypes.STRING,
unique: false,
allowNull: false
}
});
return boardMember;
};
I then want to access the data returned in a table using handlebars:
{{#each board}}
<tr>
<td>{{boardMembers.post}}</td>
<td>{{firstName}} {{surName}}</td>
<td>{{email}}</td>
</tr>
{{/each}}
Here is where I get it wrong(I think). The names and email appear, but not the post. I've tried using only post as well but to no avail. This is odd I think because the query that is generated looks like this (I removed the createdAt and updatedAt columns to make it shorter for you to read):
SELECT
`user`.`id`, `user`.`username`, `user`.`password`,
`user`.`firstName`, `user`.`surName`, `user`.`email`, `user`.`access`,
`boardMembers`.`id` AS `boardMembers.id`, `boardMembers`.`post` AS `boardMembers.post`,
`boardMembers`.`userId` AS `boardMembers.userId`
FROM
`users` AS `user`
INNER JOIN
`boardMembers` AS `boardMembers` ON `user`.`id` = `boardMembers`.`userId`;
The console.log outputs something like this(the data obviously changed):
[ Instance {
dataValues:
{ id: 2,
username: 'username',
password: 'hashedPassword',
firstName: 'User',
surName: 'Name',
email: 'user#name.com',
access: '0',
boardMembers: [Object] },
...
]
Any help is much appreciated!
Thanks,
Freece
Per the sequelize documentation the value for the include attribute is a list.
You can try with the special value include: [{ all: true, nested: true }] and see if it works for you.
Additionally you have a problem with your template becuase you have stablished a one to many relation and therefore the boardMemebers attribute of model instances are arrays.

Resources