using sequilize reference with include model for GraphQL - node.js

Good afternoon,
Im using sequilize with graphQL, I have three models
const Company= db.define('Company',{
name: {
type: DataTypes.STRING
},
icon: {
type: DataTypes.STRING
}
});
Empresa.hasMany(Producto, {as: 'products', foreignKey: 'CompanyId'});
const Product = db.define('Product',{
name: {
type: DataTypes.STRING
},
price: {
type: DataTypes.INTEGER
},
icon: {
type: DataTypes.STRING
}
});
Product.belongsTo(Company, {as: 'company', foreignKey: 'CompanyId'});
Producto.hasMany(Off, {as: 'offs', foreignKey: 'ProductID'});
const Off= db.define('Off',{
day: {
type: DataTypes.STRING
},
off: {
type: DataTypes.INTEGER
},
description: {
type: DataTypes.STRING
},
});
Off.belongsTo(Product, {as: 'product', foreignKey: 'ProductID'});
getCompany: async () => {
const companies = await Company.findAll({model:Producto, as: 'productos'}]});
return companies ;
},
its working good, I can get the name of the company and their productos
getProducto: async () => {
const products = await Producto.findAll({include: [{model:Company, as: 'company'},
{model:Off, as: 'off'}]});
return products;
},
its working good as well, I can get products and their off, nevertheless when I want
query GetCompanies {
getCompanies {
name
products {
name
off{
off
description
}
}
}
}
I can get the products, but I see a null the off, its like I can go two levels down or up, somebody know, thanks
graphQL return
{
"data": {
"GetCompanies": [
{
"name": "Exito",
"products": [
{
"name": "pescado robalo",
"off": null
},
{
"name": "carne milanesa",
"off": null
}
]
},
{
"name": "Macro",
"products": [
{
"name": "ponymalta",
"off": null
}
]
}
]
}
}

I did it with
Company.findAll({
include: [{
model: Product,
as: 'products',
include:[{ model:Off, as: 'offs' }]
}]
});

Related

Making relation one to many on sequelize node js

I've been tried of making relation of one to many on sequelize, i just wanna make the "jadwal" data have data of "dosen".
This's the JadwalModel that have the foreignKey
// Main Folder > models > JadwalModel.js
import { Sequelize } from "sequelize";
import db from "../config/Database.js";
import Dosen from "./DosenModel.js";
const { DataTypes } = Sequelize;
const Jadwal = db.define('jadwal', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
id_dosen: {
type: DataTypes.INTEGER
},
room: {
type: DataTypes.STRING
},
date: {
type: DataTypes.DATE
}
}, {
freezeTableName: true
});
// Dosen.hasMany(Jadwal, { foreignKey: 'id_dosen' });
// Jadwal.belongsTo(Dosen, { foreignKey: 'id_dosen' }); // This return ReferenceError: Cannot access 'Dosen' before initialization
export default Jadwal;
This's the Dosen model that the primaryKey/ ReferenceKey
// Main Folder > models > DosenModel.js
import { Sequelize } from "sequelize";
import db from '../config/Database.js';
import Jadwal from "./JadwalModel.js";
const { DataTypes } = Sequelize;
const Dosen = db.define('dosen', {
id_dosen: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
id_matkul: {
type: DataTypes.INTEGER
},
id_user: {
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING
},
nip: {
type: DataTypes.INTEGER
},
username: {
type: DataTypes.STRING
},
password: {
type: DataTypes.STRING
},
refresh_token: {
type: DataTypes.TEXT
}
}, {
freezeTableName: true
});
// Dosen.hasMany(Jadwal, { foreignKey: 'id_dosen' });
// Jadwal.belongsTo(Dosen, { foreignKey: 'id_dosen' });
export default Dosen;
This's the jadwal controller the file to get the data
// Main Folder > controllers > Jadwal.js
import Dosen from '../models/DosenModel.js';
import Jadwal from '../models/JadwalModel.js';
export const getJadwals = async(req, res) => {
try {
const jadwal = await Jadwal.findAll({
attributes: ['id', 'id_dosen', 'room', 'date']
}, {
include: [{ model: Dosen }]
});
res.status(200).json(jadwal);
} catch (error) {
console.log(error);
}
}
And this's the example result
// Result
[
{
"id": 1,
"id_dosen": 1,
"room": "Ruang TR 2",
"date": "2022-05-26T10:00:00.000Z"
}
]
// The result that i want is
[
{
"id": 1,
"dosen": {
"name" : "dosenName"
},
"room": "Ruang TR 2",
"date": "2022-05-26T10:00:00.000Z"
}
]
That wasn't error, i just forgot because i only fetch several field not all so i decide to delete the attributes and get the data relation
attributes: ['id', 'id_dosen', 'ruangan', 'tanggal']

MongoDB, populate nested object in array

I have a question ...
I have a schema like this :
const chatSchema = new Schema({
[...]
title: {
type: String,
required: true
},
message: [
{
content: {
type: String,
required: true
},
creator: {
type: mongoose.Types.ObjectId,
required: true,
ref: 'User'
}
}
],
[...]
});
in my Node backend, how can I have access to my creators instances inside my message array ? I don’t know how to write the query with populate ...
Thank you all ! :-)
use the following command:
...after importing chatSchema as maybe chats
module.exports.populateCreator = (req, res) => {
chats.findOne({chatID})
.populate({
path: 'message',
populate: {
path: "creator"
}
})
.then(chats => res.json(chats))
}
You can use like this
Chats.find(query)
.populate({
path: 'message',
populate: {
path: 'creator'
}
})
.exec(function(err, docs) {});
the query you are looking for is:
https://mongoplayground.net/p/2dpeZWsXR-V
db.booking.aggregate([
{
"$match": {
id: "61fdfeef678791001880da25"
}
},
{
$unwind: "$cart"
},
{
"$lookup": {
"from": "products",
"localField": "cart.product",
"foreignField": "id",
"as": "prod"
}
},
{
"$unwind": "$prod"
},
{
"$project": {
id: 1,
status: 1,
cart: [
{
id: "$cart.id",
date: "$cart.date",
timeSlots: "$cart.timeSlots",
product: {
id: "$prod.id",
name: "$prod.name",
}
}
],
}
}
])

Why sequelize returns only one result?

i got some problems while writing code, here is some information:
Models:
'use strict';
module.exports = (sequelize, DataTypes) => {
const news = sequelize.define('news', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
title: DataTypes.STRING,
slug: {
type: DataTypes.STRING(64),
unique: true
},
body: DataTypes.STRING,
postedBy: DataTypes.INTEGER
}, {});
news.associate = function(models) {
models.news.hasMany(models.news_ratings, {
as: 'rate',
foreignKey: models.news_ratings.newsId
})
};
return news;
};
///////////////
'use strict';
module.exports = (sequelize, DataTypes) => {
const news_rating = sequelize.define('news_ratings', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
user: DataTypes.INTEGER,
rating: DataTypes.INTEGER,
newsId: DataTypes.INTEGER
}, {});
news_rating.associate = function(models) {
models.news_ratings.belongsTo(models.news, {
foreignKey: models.news.id
})
};
return news_rating;
};
Controller:
router.get('/news/:from/:count', (req, res, next) => {
if (Number.isInteger(Number(req.params.from)) && Number.isInteger(Number(req.params.count))) {
models.news.findAll({
offset: Number(req.params.from),
limit: Number(req.params.count),
include: [{
as: 'rate',
model: models.news_ratings,
attributes: [
[sequelize.fn('AVG', sequelize.col('rating')), 'rate']
]
}]
})
.then(response => {
console.log(response)
res.json(response)
})
.catch(err => {
console.error(err)
res.status(500).end()
})
} else next()
})
This code returns this result (then fetching /news/0/1):
[{
"id": 1,
"title": "First new",
"slug": "demo:first_new",
"body": "New 1. This is demo ^=^",
"postedBy": 0,
"createdAt": "2020-07-22T13:53:48.000Z",
"updatedAt": "2020-07-22T13:53:48.000Z",
"rate": [
{
"rate": "-0.3333"
}
]
}]
But I have 5 news in my database!
...And then I fetch /news/0/5, i got this:
[
{
"id": 1,
"title": "First new",
"slug": "demo:first_new",
"body": "New 1. This is demo ^=^",
"postedBy": 0,
"createdAt": "2020-07-22T13:53:48.000Z",
"updatedAt": "2020-07-22T13:53:48.000Z",
"rate": [
{
"rate": "0.0000"
}
]
}
]
Look, rate is invalid! It should be -0.3333!
Can someone explain me, why this happen and how to resolve this issue?

Sequelize: Bind multiple models for join query and create custom columns

I'd like to apply a join and groupBy in Sequelize v5 that will fetch the records from five models tables and return the records as below format.
{
"data": [
{
"products": {
"id": "01",
"name": "lorium",
"description": "ipsum",
"product_images": [
{
"url": "", // From images tbl
"image_type": "Front" // From imge_types tbl
},
{
"url": "",
"image_type": "Back"
}
]
},
"vendor": {
"first_name": "john",
"last_name": "doe"
}
}
]
}
I have created separate all five models and assign association to them.
Product Model::
const Product = SQLize.define('product', {
id: { type: DataTypes.INTEGER.UNSIGNED, autoIncrement: true, primaryKey: true, }
product_title: { type: new DataTypes.STRING(255) },
vendor_id: { type: DataTypes.INTEGER.UNSIGNED }
});
Product.hasMany(ProductImages, {foreignKey: 'product_id', targetKey: 'id', as :'product_img_refs'})
export { Product };
Vendor Model::
const Vendor = SQLize.define('vendor', {
id: { type: DataTypes.INTEGER.UNSIGNED, autoIncrement: true, primaryKey: true, },
first_name: { type: DataTypes.STRING(100) },
last_name: { type: DataTypes.STRING(100) }
});
Product.belongsTo(Vendor, {foreignKey: 'id'})
Vendor.hasOne(Product, {foreignKey: 'id'})
export { Vendor }
Product Images Model::
const ProductImages = SQLize.define('product_images', {
id: { type: DataTypes.INTEGER.UNSIGNED, autoIncrement: true, primaryKey: true, },
product_id: { type: DataTypes.INTEGER },
product_image_id: { type: DataTypes.INTEGER }
img_type_id: { type: DataTypes.INTEGER }
});
export {ProductImages}
Images Model::
const ImagesModel = SQLize.define('images', {
id: { type: DataTypes.INTEGER.UNSIGNED, autoIncrement: true, primaryKey: true, },
img_url: { type: DataTypes.STRING }
});
export { ImagesModel }
Image Types Model::
const ImageTypes = SQLize.define('image_types', {
id: { type: DataTypes.INTEGER.UNSIGNED, autoIncrement: true, primaryKey: true, },
image_type: { type: DataTypes.STRING }
});
export { ImageTypes }
Below is the repository file on which i have performed the SQLize operation: Updated::
public async getProductData() {
var prodData = Product.findAll({
include: [
{ model: Vendor, as: 'vendor' },
{ model: ProductImages, as: 'product_img_refs' }
]
});
return prodData;
}
I am not getting the correct way to bind the all models that will return me a result as described in the above json format.
To get the nested output as shown in the question, you would need to create associations between the following:
ProductImages and ImagesModel
ProductImages and ImageTypes
Once done, you can nest the models in the findAll options as shown below:
// Create associations (depends on your data, may be different)
ProductImages.hasOne(ImagesModel);
ProductImages.hasOne(ImageTypes);
// Return product data with nested models
let prodData = Product.findAll({
include: [
{ model: Vendor, as: 'vendor' },
{
model: ProductImages, as: 'product_img_refs',
include: [
{ model: ImagesModel }, // Join ImagesModel onto ProductImages (add aliases as needed)
{ model: ImageTypes } // Join ImageTypes onto ProductImages (add aliases as needed)
]
}
]
});
I found the issue. you were trying to include ProductImages model into Vendor. As per your association, ProductImages associate with Product not with Vendor.
So please try this
let prodData = Product.findAll({
include: [
{ model: Vendor, as: 'vendor' },
{ model: ProductImages }
]
});

Sequelize set associated value

I have two models, Employees and Offices. Every Employee belongs to one Office, and an Office has many Employees.
I am having difficulty figuring out how to update an Employee's office using Sequelize.
The Employee model is as follows:
let Employee = sequelize.define("Employee", {
id: {
field: 'id',
type: DataTypes.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: false
},
name: {
field: 'name',
type: DataTypes.STRING(255),
allowNull: false
}
}, {
freezeTableName: true,
timestamps: false,
deletedAt: false
})
Employee.associate = models => {
Employee.belongsTo(models.Office, {
foreignKey: 'id'
})
}
The Office model is as follows:
let Office = sequelize.define("Office", {
id: {
field: 'id',
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
field: 'name',
type: DataTypes.STRING(255),
allowNull: false
}
}, {
freezeTableName: true,
tableName: 'Lkup_Office',
timestamps: false,
deletedAt: false
})
Office.associate = models => {
Office.hasMany( models.Employee, {
foreignKey: 'id'
})
}
In the database I have the following Employee:
{
"id": "2",
"name" : "John",
"office": {
"id": 2,
"name" : "Seattle"
}
}
... and the following Offices:
[
{
"id": 1,
"name" : "Chicago"
},
{
"id": 2,
"name" : "Seattle"
}
]
I want to change the ID of Employee(1)'s office from 2 ('Seattle') to 1 ('Chicago'); the problem is that with the following query
// PUT /2/office/1
router.put('/:employeeId/office/:officeId', (req, res) => {
models.Employee.findOne({
where:{id:req.params.employeeId},
include:[{model:models.Office}]
}).then( employee => {
models.Office.findOne({
where:{id:req.params.officeId},
include:[{model:models.Employee}]
}).then( office => {
employee.setOffice( office ).then( result => {
res.send( result )
})
})
})
})
... my Employee's office is not updated:
{
"id": "2",
"name" : "John"
"office": {
"id": 2
"name" : "Seattle"
}
}
It doesn't, in fact, do anything at all: no errors, the DB isn't changed. I have a suspicion that there's something I'm not doing correctly, but Sequelize isn't throwing any errors.
router.put('/:employeeId/office/:officeId', (req, res) => {
/*In this first part, I just separated the two queries into two
separate variables*/
let employeeInfo = models.Employee.findOne({
where: {
id: req.params.employeeId
},
include: [{
model: models.Office
}]
});
let officeInfo = models.Office.findOne({
where: {
id: req.params.officeId
},
include: [{
model: models.Employee
}]
});
/*In this next part, we have to use Promise.all, which comes with
bluebird, which is already a part of Sequelize.js. How this next
part is executed will depend on how you have your Sequelize.js code
structured in your application. This may require some trial and error*/
models.sequelize.Promise.all([employeeInfo, officeInfo]).then(([Employee, Office])=> {
return Employee.setOffice(Office);
}).catch(err => {
console.log(err);
});
});

Resources