How to write custom where condition raw query? - javascript

How to write this sql query as sequelize query?
select * from chats where senderId + receiverId = 25
I want to use above query where condition in where clause of sequelize which is written below.
const options = {
page: req.params.pageNo, // Default 1
paginate: 25, // Default 25
order: [['id', 'DESC']],
include: [
{
model: db.users,
required: true,
as: 'senderUser',
attributes: ['id', 'name', 'email', 'mobileNumber', 'profilePic'],
},
{
model: db.users,
required: true,
as: 'receiverUser',
attributes: ['id', 'name', 'email', 'mobileNumber', 'profilePic'],
},
],
where: {
//here i need condition
},
};
db.chats
.paginate(options)
.then(result => {
let apiData = { pages: result.pages, total: result.total, chats: result.docs };
return _RL.apiResponseOk(res, 'Messages', apiData);
})
.catch(error => {
console.log(error);
return _RL.serverError(res);
});

You'll have to write aggregate query
await Chats.aggregate([
{
$addFields:{
'total':{$add:['$senderId','$receiverId']}
}
},
{
$match:{
'total':{$eq:25}
}
}
])
I'm assuming both senderId & receiverId are Numbers

Related

Postgres DatabaseError [SequelizeDatabaseError]: syntax error at or near "IN"

I have end-point which is supposed to delete record from DB:
delete: async(roleId, actionId) => {
const actionrole = await ActionRoleModel.findAll({
where: {
roleId: roleId,
actionId: actionId
},
});
return await actionrole[0].destroy();
}
That [0] has to be here, because actionrole looks like [{...}].And here is the model:
'use strict';
module.exports = (sequelize, DataTypes) => {
var ActionRole = sequelize.define('actionroles', {
actionId: {
type: "UNIQUEIDENTIFIER",
field: "actionid"
},
roleId: {
type: "UNIQUEIDENTIFIER",
field: "roleid"
},
createdAt: {
field: "createdat",
type: DataTypes.DATE
},
updatedAt: {
field: "updatedat",
type: DataTypes.DATE
},
}, {});
ActionRole.associate = function(models) {
// associations can be defined here
};
ActionRole.removeAttribute('id');
return ActionRole;
};
But as an error in terminal I get
DatabaseError [SequelizeDatabaseError]: syntax error at or near "IN"
And here is SQL:
DELETE FROM "actionroles"
WHERE IN (
SELECT FROM "actionroles"
WHERE "roleid" = '53549d62-cd2a-497f-9d1c-1ee1901261ab' AND "actionid" = '6c70bf65-30fd-4640-91d0-8fbda85c4dd5'
LIMIT 1)
What's wrong? How can I fix that?
For anyone using Sequelize version 3 and above it looks like:
Model.destroy({
where: {
// conditions
}
})
So, in this case it would be look like this:
return await ActionRoleModel.destroy({
where: {
roleId: roleId,
actionId: actionId
}
});
And it works!

Function which returns a promise not working as expected

I have this promise chain in my code and it works just fine. Document actually has a value and is not null
...
.then(() => {
return db.document.findOne({
where: {
id: _document.get('id', req.transaction)
},
include: [{
model: db.documentChildren,
attributes: ['id', 'reference', 'uri', 'contentType', 'type', 'page']
},
{
model: db.tag,
attributes: ['id', 'key', 'value'], // We don't want meta columns
through: { attributes: [] } // Exclude join table
}],
transaction: req.transaction
})
})
.then(document => {
console.log('document = ', document)
...
Now I want to abstract that query into a function so that it can be reused.
I would have thought this would work, but for some reason document is always null and when I run the generated query it does have a result.
Why is document null when abstracting this query into its own function?
function findOneDocumentQuery (db, id, transaction) {
return db.document.findOne({
where: {
id: id
},
include: [{
model: db.documentChildren,
attributes: ['id', 'reference', 'uri', 'contentType', 'type', 'page']
},
{
model: db.tag,
attributes: ['id', 'key', 'value'], // We don't want meta columns
through: { attributes: [] } // Exclude join table
}],
transaction: transaction
})
}
...
.then(() => {
return findOneDocumentQuery(db, _document.get('id', req.transaction))
})
.then(document => {
console.log('document = ', document)
...
I think the bracket to findOneDocumentQuery is wrong, it should be:
return findOneDocumentQuery(db, _document.get('id'), req.transaction);

Sequelize create include existing object

I'm having an issue with sequelize on create with associated model with an "unique" value. It works when I create a "book" with a new "category", but if the "category" already exists it throws an error because it tried to duplicate an "unique" value. Is there a way to make sequelize.create try to use findAndCreate on a associated model?
My setup
Book:
const Book = sequelize.define('book', {
title: Sequelize.STRING,
})
Category:
const Category = sequelize.define('category', {
id: Sequelize.BIGINT,
name: {
type: Sequelize.STRING,
unique: true,
},
})
and the relationship:
Book.belongsTo(Category, { foreignKey: 'category_id' })
So, when i create a book i can write:
Book.create(
{
title: 'Book',
category: {
name: 'Foo'
}
}, {
include: [
{
model: Category
}
]
}
)
if after that I create another book:
Book.create(
{
title: 'Another Book',
category: {
name: 'Foo'
}
}, {
include: [
{
model: Category
}
]
}
)
it throws the error saying category.name must be unique
For anyone with the same question, this was my final solution:
On my services.js I created the function create that receives a request(req) and all my models already initialized.
create: (req, models) => {
const { category, ...rest } = req.body
if (category && category.name && !rest.category_id) {
return models.Category
.findOrCreate({
where: {
name: category.name
}
})
.then(([returnedCategory]) => {
return models.Book.create(
{
...rest,
category_id: returnedCategory.id
},
{ ...defaultOptions(models) }
)
})
} else {
return models.Book.create(rest, { ...defaultOptions(models) })
}
},
defaultOptions looks like this:
const defaultOptions = models => {
return {
attributes: {
exclude: ['category_id', 'created_at', 'updated_at'],
},
include: [
{ model: models.Category, attributes: ['id', 'name'] },
],
}
}

Sequelize include an attribute from junction table

I'm building a shop, where in the database i have orders and items. Here's the code for the models:
Item:
var Sequelize = require('sequelize')
var sequelize = require('./sequelize')
var Item = sequelize.define('item', {
image: {
type: Sequelize.STRING,
allowNull: false
},
itemName: {
type: Sequelize.STRING,
allowNull: false,
field: 'item_name'
},
price: {
type: Sequelize.INTEGER,
allowNull: false
}
})
module.exports = Item
Order:
var Sequelize = require('sequelize')
var sequelize = require('./sequelize')
var Order = sequelize.define('order', {
orderNumber: {
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4
},
shop: {
type: Sequelize.INTEGER
},
location: {
type: Sequelize.STRING
}
})
module.exports = Order
They are related through belongs to many:
Item.belongsToMany(Order, {through: OrderItem})
Order.belongsToMany(Item, {through: OrderItem})
The OrderItem has an additional field, 'count', which i need to return:
var Sequelize = require('sequelize')
var sequelize = require('./sequelize')
var OrderItem = sequelize.define('OrderItem', {
count: Sequelize.INTEGER
})
module.exports = OrderItem
However, when i try to include the OrderItem model, it doesn't work. No errors, nothing. The query just doesn't return:
Order.findAll({
where: {
userId: userId
},
include: [{
model: Item,
include: [OrderItem]
}]
}).then(orders => {
console.log(orders)
res.status(200).json(orders)
})
How to get what i need from sequeilize?
You may try something like this:
Order.findAll({
where: {
userId: userId
},
include: [{ model: Item,
as:'item',
through:{attributes:['count']} // this may not be needed
}]
}).then(orders => {
console.log(orders)
res.status(200).json(orders)
})
Also, your models must have a right naming strategy. E.g. :
Item - must have itemId field instead of itemNumber,
Order - must have orderId as primary field
OrderItem's structure:
var OrderItem = sequelize.define('OrderItem', {
orderId: Sequelize.INTEGER,
itemId: Sequelize.INTEGER,
count: Sequelize.INTEGER
})
Another one is to use direct names of related fields and models when you use belongsToMany()
More here: http://docs.sequelizejs.com/en/latest/docs/associations/
Turns out that the OrderItem is already nested inside the Item object. However, this doesn't make a nice return format , so the question is still open.
I know this is year later, but yet..
You can use the property joinTableAttributes to get a junction table fields .
for example :
Order.findAll({
where: {
userId: userId
},
joinTableAttributes: ['count'],
include: [{
model: Item,
}]
}).then(orders => {
console.log(orders)
res.status(200).json(orders)
})
I am using Graphql and I had the same problem with the formatting. I did a small map after getting the result.
For example:
let orders = await Order.findAll({
where: {
userId: userId
},
include: [{ model: Item,
as:'item',
through:{attributes:['count']}
}]
});
let ordersWithCount = orders.map((o) => {
let orderWithCount = {};
orderWithCount = o;
orderWithCount.count = o.OrderItem.count;
return orderWithCount;
});

Sequelize WHERE NOT EXISTS()

I have a many to many relations that looks like this:
var Genres = db.define('Movie', {
name: {
type: Sequelize.STRING(100),
allowNull: false
},
description: {
type:Sequelize.STRING(),
allowNull: true
},
thumbnail: {
type: Sequelize.BLOB(),
allowNull: true
},
urlposter: {
type: Sequelize.STRING(245),
allowNull: true
}
});
var Users = db.define('User', {
username: {
type: Sequelize.STRING(25),
allowNull: false
},
password: {
type: Sequelize.STRING(25),
allowNull: false
}
});
Movies.belongsToMany(Users, {through: UM, foreignKey: 'Id_Movies'});
Users.belongsToMany(Movies, {through: UM, foreignKey: 'Id_Users'});
what I will do is return all Movies that have no link to a specific user
this is my SQL query i want to achive:
SELECT m.*
FROM Movies m
WHERE NOT EXISTS(SELECT NULL
FROM Users_Movies sc
WHERE sc.Id_Movies = m.id AND sc.Id_Users = 1)
This is the closest I've got but this just return all movies that have a link u user with ID 1
Movies.findAll({
include: [
// {
// model:Genres,
// through:{attributes:[]}
// },
{
model:Users,
through:{attributes:[]},
where: {id: 1},
required: true,
}],
})
.then(function(movies){
done(null, movies);
})
.catch(function(error){
done(error, null);
});
But I want to invert it.
right now my only option is to make 2 queries one with all movies and one with all movies that have a link and loop through the list and remove them from the first list.. this is not pretty code.
I know that I'm late on the matter, but I think that using the literal 'users.id IS NULL' in the query's 'where' will do the trick:
Movie.findAll({
where: sequelize.literal("users.id IS NULL"),
include: [
{
model: Users,
through: { attributes: [] }
}],
})
.then(function (movies) {
done(null, movies);
})
.catch(function (error) {
done(error, null);
});
This solutions is based on the following Github issue: https://github.com/sequelize/sequelize/issues/4099
Use rawQuery
const projects = await sequelize.query('SELECT * FROM projects', {
model: Projects,
mapToModel: true // pass true here if you have any mapped fields
});

Categories