Auto increment id with sequelize in MySQL - mysql

I have the following model in NodeJS with sequelize and a MySQL database:
var Sequelize = require('sequelize');
var User = sequelize.define('user', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
...
};
I am trying to add a new user to my databse with the below code:
sequelize.transaction().then(function(t) {
User.create({/* User data without id */}, {
transaction: t
}).then(function() {
t.commit();
}).catch(function(error) {
t.rollback();
});
});
After that, I am getting the next error:
Executing (47f19f7b-a02d-4d72-ba7e-d5045520fffb): START TRANSACTION;
Executing (47f19f7b-a02d-4d72-ba7e-d5045520fffb): SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Executing (47f19f7b-a02d-4d72-ba7e-d5045520fffb): SET autocommit = 1;
Executing (47f19f7b-a02d-4d72-ba7e-d5045520fffb): INSERT INTO `user` (`id`, /* next fields */) VALUES (DEFAULT, /* next values */);
Executing (47f19f7b-a02d-4d72-ba7e-d5045520fffb): ROLLBACK;
And the error message:
[SequelizeDatabaseError: ER_NO_DEFAULT_FOR_FIELD: Field 'id' doesn't have a default value]
name: 'SequelizeDatabaseError',
message: 'ER_NO_DEFAULT_FOR_FIELD: Field \'id\' doesn\'t have a default value'
However, if I manually set the id value, it works. It seems sequelize is trying to set a default value in the id field, instead setting an autoincrement integer. I have defined this field as autoIncrement in my database too.
How could I do this insertion? Do I have to set the id manually?
EDIT
This is my table definition:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` varchar(9) NOT NULL,
`name` varchar(20) NOT NULL,
`email` varchar(30) DEFAULT NULL,
`birthdate` date NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uid_UNIQUE` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

You must be sure you're not even sending the id key at all.
I have done a quick minimal test and it seemed to work great:
var Sequelize = require('sequelize');
var sequelize = new Sequelize('cake3', 'root', 'root', {
define: {
timestamps: false
},
});
var User = sequelize.define('user1', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: {
type: Sequelize.STRING
}
});
sequelize.transaction().then(function(t) {
User.create({name:'test'}, {
transaction: t
}).then(function() {
t.commit();
}).catch(function(error) {
console.log(error);
t.rollback();
});
});
Table dump:
CREATE TABLE `user1s` (
`id` int(11) NOT NULL,
`name` varchar(20) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
ALTER TABLE `user1s`
ADD PRIMARY KEY (`id`);
ALTER TABLE `user1s`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=1;

In migration, add this line of code:
await queryInterface.sequelize.query("ALTER TABLE table_name AUTO_INCREMENT = 1000000;");

Related

Why am I getting "UnhandledPromiseRejectionWarning: Error at Query.run" trying to implement one to many relation with sequelize, mysql and Nodejs?

I am trying to establish One-to-many relation using sequelize, MySQL and Node-Express I am getting the following error.
server is running on port : 8080
Executing (default): SELECT 1+1 AS result
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'products' AND TABLE_SCHEMA = 'node_sequelize_api_db'
connected to db
Executing (default): CREATE TABLE IF NOT EXISTS `products` (`id` INTEGER NOT NULL auto_increment , `title` VARCHAR(255) NOT NULL, `price` INTEGER, `description` TEXT, `published` TINYINT(1), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `products`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'reviews' AND TABLE_SCHEMA = 'node_sequelize_api_db'
Executing (default): CREATE TABLE IF NOT EXISTS `reviews` (`id` INTEGER NOT NULL auto_increment , `rating` INTEGER, `description` TEXT, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `productId` INTEGER, PRIMARY KEY (`id`), FOREIGN KEY (`productId`) REFERENCES `products` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB;
(node:15924) UnhandledPromiseRejectionWarning: Error
at Query.run (/home/grace/Desktop/_SOFTWARE_ENGINEER/FULLSTACK/node_sequelize/node_modules/sequelize/lib/dialects/mysql/query.js:52:25)
at retry (/home/grace/Desktop/_SOFTWARE_ENGINEER/FULLSTACK/node_sequelize/node_modules/sequelize/lib/sequelize.js:314:28)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:15924) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:15924) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
THIS IS MY Model/index.js where the relation happens
require('dotenv').config();
const {Sequelize, DataTypes} = require('sequelize')
const sequelize = new Sequelize(
process.env.DB,
process.env.USER,
process.env.PASSWORD,{
host:process.env.HOST,
dialect: process.env.DIALECT,
operatorsAlias: false,
/*pool:{
max: dbConfig.pool.max,
min: dbConfig.pool.min,
acquire: dbConfig.pool.acquire,
idle: dbConfig.pool.idle
}*/
}
)
sequelize.authenticate()
.then(() =>{
console.log('connected to db')
})
.catch(err =>{
console.log('Error' + err)
})
const db = {}
db.Sequelize = Sequelize
db.sequelize = sequelize
db.products = require('./productModel.js')(sequelize, DataTypes);
db.reviews = require('./reviewModel.js')(sequelize, DataTypes);
//it won't create the table over and over
db.sequelize.sync({force: false})
.then(()=>{
console.log('yes re-sync done!')
})
//implement One-to-Many relationship
db.products.hasMany(db.reviews,{
foreignKey: 'product_id',
as: 'review',
})
db.reviews.belongsTo(db.products,{
foreignKey: 'product_id',
as: 'product'
})
Model/productModel.js
module.exports = (sequelize, DataTypes) => {
return sequelize.define("product", {
title: {
type: DataTypes.STRING,
allowNull: false
},
price: {
type: DataTypes.INTEGER
},
description: {
type: DataTypes.TEXT
},
published: {
type: DataTypes.BOOLEAN
}
})
}
Review Model
module.exports = (sequelize, DataTypes) => {
return sequelize.define("review", {
rating: {
type: DataTypes.INTEGER,
},
description: {
type: DataTypes.TEXT
}
})
}
Product controller
//7. connect 1 to many relation Roduct to Review
const getProductReviews = async (req, res) =>{
try{
const data = await Product.findAll({include: Review})
}catch(e){
console.error(e)
}
}
module.exports ={
addProduct,
getAllProducts,
getOneProduct,
updateProduct,
deleteProduct,
getPublishedProduct,
getProductReviews
}
If I remove the following code from Model/index.js
//implement One-to-Many relationship
db.products.hasMany(db.reviews,{
foreignKey: 'product_id',
as: 'review',
})
db.reviews.belongsTo(db.products,{
foreignKey: 'product_id',
as: 'product'
})
Everything runs smoothly, so I am convinced that the error comes from the relationship I am trying to implement, I went through the documentation try to implement it differently but I am still getting the same error.
In your code you call sync(..) method which returns Promise. And looks like this promise is rejected. So try to replace
db.sequelize.sync({force: false})
.then(()=>{
console.log('yes re-sync done!')
})
with something like
db.sequelize.sync({force: false})
.then(()=>{
console.log('yes re-sync done!')
})
.catch(e=>console.log("Can't syncronize",e));

In nodejs, how to insert data into MySQL using sequelize.bulkcreate?

I have googled and looked up the codes creating data using sequelize.
However, writers are too good to overlook this pity but basic issue.
Where do I write the code?
Here is my directory.
Modeling
/config
config.json
/migrations
(empty)
/models
index.js
platoon.js
section.js
squad.js
team.js
/node_moduels
/seeders
(empty)
app.js
package-lock.json
package.json
The code I am trying to add on my code is
Team.bulkCreate([
{ name: 'team1', platoonID: "4" },
{ username: 'team2', platoonID: "4" },
{ username: 'team3', platoonID: "4" },
{ username: 'team4', platoonID: "4" },
{ username: 'team5', platoonID: "4" }
]).then(() => { // Notice: There are no arguments here, as of right now you'll have to...
return Team.findAll();
}).then(teams => {
console.log(teams) // ... in order to get the array of user objects
})
But the code returns
Executing (default): INSERT INTO `teams` (`id`,`name`,`created_at`,`platoonID`) VALUES (NULL,'1팀',now(),'4'),(NULL,NULL,now(),'4'),(NULL,NULL,now(),'4'),(NULL,NULL,now(),'4'),(NULL,NULL,now(),'4');
Executing (default): CREATE TABLE IF NOT EXISTS `platoons` (`id` INTEGER NOT NULL auto_increment , `name` VARCHAR(20) NOT NULL UNIQUE, `created_at` DATETIME NOT NULL DEFAULT now(), PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
(node:15874) UnhandledPromiseRejectionWarning: SequelizeDatabaseError: Table 'nodejs.teams' doesn't exist
at Query.formatError (/Users/mac/Desktop/modeling/node_modules/sequelize/lib/dialects/mysql/query.js:239:16)
at Query.run (/Users/mac/Desktop/modeling/node_modules/sequelize/lib/dialects/mysql/query.js:54:18)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:15874) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:15874) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Executing (default): SHOW INDEX FROM `platoons` FROM `nodejs`
Executing (default): CREATE TABLE IF NOT EXISTS `sections` (`id` INTEGER NOT NULL auto_increment , `name` VARCHAR(20) NOT NULL UNIQUE, `created_at` DATETIME NOT NULL DEFAULT now(), `platoonID` INTEGER, PRIMARY KEY (`id`), FOREIGN KEY (`platoonID`) REFERENCES `platoons` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
Executing (default): SHOW INDEX FROM `sections` FROM `nodejs`
Executing (default): CREATE TABLE IF NOT EXISTS `squads` (`id` INTEGER NOT NULL auto_increment , `name` VARCHAR(20) NOT NULL UNIQUE, `created_at` DATETIME NOT NULL DEFAULT now(), `platoonID` INTEGER, PRIMARY KEY (`id`), FOREIGN KEY (`platoonID`) REFERENCES `platoons` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
Executing (default): SHOW INDEX FROM `squads` FROM `nodejs`
Executing (default): CREATE TABLE IF NOT EXISTS `teams` (`id` INTEGER NOT NULL auto_increment , `name` VARCHAR(20) NOT NULL UNIQUE, `created_at` DATETIME NOT NULL DEFAULT now(), `sectionID` INTEGER, `squadID` INTEGER, `platoonID` INTEGER, PRIMARY KEY (`id`), FOREIGN KEY (`sectionID`) REFERENCES `sections` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, FOREIGN KEY (`squadID`) REFERENCES `squads` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, FOREIGN KEY (`platoonID`) REFERENCES `platoons` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
Executing (default): SHOW INDEX FROM `teams` FROM `nodejs`
connection succeed
I wrote this code in models/index.js.
I guess the code should be written in models/index.js, but it seems not.
How can I insert bulk data into MySQL using sequelize.bulkcreate?
models/index.js
const Sequelize = require('sequelize');
const Team = require("./team");
const Section = require("./section");
const Squad = require("./squad");
const Platoon = require("./platoon");
const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {};
const sequelize = new Sequelize(config.database, config.username, config.password, config);
db.sequelize = sequelize;
db.Team = Team;
db.Section = Section;
db.Squad = Squad;
db.Platoon = Platoon;
Team.init(sequelize);
Section.init(sequelize);
Squad.init(sequelize);
Platoon.init(sequelize);
Team.associate(db);
Section.associate(db);
Squad.associate(db);
Platoon.associate(db);
//Team.bulkCreate([
// { name: 'team1', platoonID: "4" },
// { username: 'team2', platoonID: "4" },
// { username: 'team3', platoonID: "4" },
// { username: 'team4', platoonID: "4" },
// { username: 'team5', platoonID: "4" }
//]).then(() => {
// return Team.findAll();
//}).then(teams => {
// console.log(teams)
//})
module.exports = db;
Team.bulkCreate([
{ name: 'team1', platoonID: "4" },
{ username: 'team2', platoonID: "4" },
{ username: 'team3', platoonID: "4" },
{ username: 'team4', platoonID: "4" },
{ username: 'team5', platoonID: "4" }
]).then(() => {
return Team.findAll();
}).then(teams => {
console.log(teams)
})
models/team.js
const Sequelize = require("sequelize");
module.exports = class Team extends Sequelize.Model{
static init(sequelize) {
return super.init({
name : {
type : Sequelize.STRING(20),
allowNull : false,
unique : true,
},
created_at : {
type : Sequelize.DATE,
allowNull : false,
defaultValue : sequelize.literal('now()'),
},
},{
sequelize,
timestamps : false,
underscored : false,
modelName : 'Team',
tableName : 'teams',
paranoid : false,
charset : 'utf8',
collate : 'utf8_general_ci',
});
}
static associate(db) {
db.Team.belongsTo(db.Section, {
foreignKey : "sectionID",
targetKey : 'id'
});
db.Team.belongsTo(db.Squad, {
foreignKey : "squadID",
targetKey : 'id'
});
db.Team.belongsTo(db.Platoon, {
foreignKey : "platoonID",
targetKey : 'id'
});
};
}
I have tried to write the code in models/index.js file but it fails.
Please help where to write the code

Gatsby - Getting undefined for MySQL id

I want to get into Gatsby.
My current problem is, that i can not get the "id" from mysql database.
The result for "id" (Primary "AUTO_INCREMENT") is "mysql__Homepage__undefined" (expected "16" - represented in DB))
The result for "id2" is "4" (represented in DB)
My table structure
CREATE TABLE `homepage` (
`id` int(5) UNSIGNED NOT NULL,
`id2` smallint(1) UNSIGNED NOT NULL,
`release` char(3) NOT NULL DEFAULT 'on',
`headline` varchar(250) NOT NULL,
`lastmodified` varchar(100) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
My Gatsby GQL is
allMysqlHomepage {
edges {
node {
headline
id
id2
}
}
}
Result for id
mysql__Homepage__undefined
Result for id2
4
Someone run into same problem?
Best regards
Found the solution:
In gatsby-config.js I had to set the idFieldName to my id field from db:
{
resolve: `gatsby-source-mysql`,
options: {
connectionDetails: {
host: 'localhost',
user: 'test',
password: 'test',
database: 'test'
},
queries: [
{
statement: 'SELECT * FROM test',
idFieldName: 'id',
name: 'test'
}
]
}
}
```

Loopback 4 and constraints in MySQL relations

I am getting into Loopback 4, coming from Sequelize and with a bit of experience with TypeORM.
My question is why in Loopback 4 the relations doesn't get constraints. I have seen https://loopback.io/doc/en/lb4/todo-list-tutorial-sqldb.html#specify-the-foreign-key-constraints-in-todo-model, but I don't get why it doesn't do it automatically, or if I'm doing something wrong.
Lets see an example with the same models for the three ORMS: a User model that can have many Post:
User --* Post
Sequelize:
User:
const User = sequelize.define(
'User',
{
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
name: {
type: Sequelize.STRING,
},
},
{}
);
User.associate = function(models) {
User.hasMany(models.Post, { onDelete: 'CASCADE' });
};
Post:
const Post = sequelize.define(
'Post',
{
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
title: {
type: Sequelize.STRING,
},
text: {
type: Sequelize.TEXT,
},
},
{}
);
Post.associate = function(models) {
Post.belongsTo(models.User, { onDelete: 'CASCADE' });
};
Result in MYSQL:
CREATE TABLE IF NOT EXISTS `test_sequelize`.`Users` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
AUTO_INCREMENT = 3
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `test_sequelize`.`Posts` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NULL DEFAULT NULL,
`text` TEXT NULL DEFAULT NULL,
`UserId` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `UserId` (`UserId` ASC) ,
CONSTRAINT `posts_ibfk_1`
FOREIGN KEY (`UserId`)
REFERENCES `test_sequelize`.`Users` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
AUTO_INCREMENT = 4
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;
Ok, the constraints are there.
Now lets try with TypeORM:
TypeORM:
User:
import { Post } from './Post';
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: string;
#Column()
name: string;
#OneToMany(type => Post, post => post.user, { onDelete: 'CASCADE' })
posts: Post[];
}
Post:
import { User } from './User';
import { PostHasTag } from './PostHasTag';
import { Tag } from './Tag';
#Entity()
export class Post {
#PrimaryGeneratedColumn()
id: number;
#Column()
title: string;
#Column({ type: 'text' })
text: string;
#ManyToOne(type => User, user => user.posts)
user: User;
}
And this is the result in MySQL:
CREATE TABLE IF NOT EXISTS `test_typeorm`.`user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
AUTO_INCREMENT = 3
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `test_typeorm`.`post` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NOT NULL,
`text` TEXT NOT NULL,
`userId` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `FK_5c1cf55c308037b5aca1038a131` (`userId` ASC) ,
CONSTRAINT `FK_5c1cf55c308037b5aca1038a131`
FOREIGN KEY (`userId`)
REFERENCES `test_typeorm`.`user` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
AUTO_INCREMENT = 4
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;
Everything ok, constraints there. Now with Loopback 4.
Loopback 4:
The models, repositories, controllers and relations are generated by the cli, but I will only post the models:
User:
import {Post} from './post.model';
#model({settings: {}})
export class User extends Entity {
#property({
type: 'number',
id: true,
generated: true,
})
id?: number;
#property({
type: 'string',
required: true,
})
name: string;
#hasMany(() => Post)
posts: Post[];
constructor(data?: Partial<User>) {
super(data);
}
}
export interface UserRelations {
// describe navigational properties here
}
export type UserWithRelations = User & UserRelations;
Post:
import {Entity, model, property} from '#loopback/repository';
#model({settings: {}})
export class Post extends Entity {
#property({
type: 'number',
id: true,
generated: true,
})
id?: number;
#property({
type: 'string',
required: true,
})
title: string;
#property({
type: 'string',
})
text?: string;
#property({
type: 'number',
})
userId?: number;
constructor(data?: Partial<Post>) {
super(data);
}
}
export interface PostRelations {
// describe navigational properties here
}
export type PostWithRelations = Post & PostRelations;
And the MySQL:
CREATE TABLE IF NOT EXISTS `test_loopback`.`Post` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(512) NOT NULL,
`text` VARCHAR(512) NULL DEFAULT NULL,
`userId` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `test_loopback`.`User` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(512) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;
And as you may see, there are no constraints there. Am I doing something wrong? Is this expected behaviour?
This is a known short-coming of LoopBack, see the discussion in the following GitHub issues:
lb4 relations referential integrity for hasMany/belongsTo https://github.com/strongloop/loopback-next/issues/1718
Database migration should create SQL constraints for relations https://github.com/strongloop/loopback-next/issues/2332
and loosely related: Memory connector should enforce referential integrity https://github.com/strongloop/loopback-next/issues/2333
Loopback 4 and constraints in MySQL relations
#model({
settings: {
foreignKeys: {
fk_todo_todoListId: {
name: 'fk_todo_todoListId',
entity: 'TodoList',
entityKey: 'id',
foreignKey: 'todolistid',
},
},
},
})
export class Todo extends Entity {
//etc.
}
https://loopback.io/doc/en/lb4/todo-list-tutorial-sqldb.html#specify-the-foreign-key-constraints-in-todo-model

Parse the result of a mysql select query on multiple tables with nodeJS

I'm a nodeJS beginner and am trying to learn it by creating a blog. To do so, I have three tables
CREATE TABLE `articles` (
`article_id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`content` longtext NOT NULL,
`image` varchar(255) NOT NULL,
`created` datetime NOT NULL,
`author_id` int(11) NOT NULL,
PRIMARY KEY (`article_id`)
)
CREATE TABLE `authors` (
`author_id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(255) NOT NULL,
PRIMARY KEY (`author_id`)
)
CREATE TABLE `comments` (
`comment_id` int(11) NOT NULL AUTO_INCREMENT,
`comment_content` longtext NOT NULL,
`created` datetime NOT NULL,
`comment_author` varchar(255) NOT NULL,
`id_article` int(11) NOT NULL,
PRIMARY KEY (`comment_id`)
)
On my page, I want to get all my articles, with their associated authors and comments.
This is my node code to get the data :
app.get('/api/articles', function(req, res){
connection.query('SELECT * FROM articles LEFT JOIN authors ON articles.author_id = authors.author_id LEFT JOIN comments ON articles.article_id = comments.id_article', function(err, row, fields){
if(!err){
res.json(rows);
}else
console.log('Error');
});
});
This query returns the data I need, but I want to parse it to get something that I can use easier in the front part, like
[
{
article_id: 1,
content: 'test',
title: 'test',
image: '',
author: {
author_id: 1,
email: 'test#test.com'
},
comments: [
{
comment_id: 1,
comment_content: 'test',
comment_author: 'test'
},
{
comment_id: 2,
comment_content: 'test',
comment_author: 'test'
}
]
}
]
Instead of the current return that looks like
[
{
article_id: 1,
title: 'test',
content: 'test',
image: '',
author_id: 1,
email: 'test#test.com',
comment_id: 1,
comment_content: 'test',
comment_author: 'test
}
]
I spent some time looking for something to do it, but couldn't find anything, so if someone knows how to do it, I'd be very grateful.
Thanks
You'll need to do two things:
(1) make sure you are sorting by article_id in your query
(2) create a tiny state machine, keeping track of the article_id, and loop through each record aggregating the comments. if your article_id changes, write the record to the table and move on to the next article:
var table = [];
var lastid = -1;
var article = {};
for(var i=0;i<rows.length;i++) {
var row = rows[i];
if (row.article_id!==lastid) {
//The id has changed, so create a new article
if (article.article_id) {
//If this isnt the first time looping, add the last article to the table
table.push(article);
}
article = {};
//create the structure you want
article.article_id = row.article_id;
article.title = row.title,
article.content = row.content,
article.image = row.image,
article.author = {
author_id: row.author_id,
email: row.email,
};
//comments go in this array. add the first one
article.comments = [{
comment_id:row.comment_id,
comment_content:row.commment_content,
comment_author:row.comment_author
}];
} else {
//same article, new comment
article.comments.push({
comment_id:row.comment_id,
comment_content:row.commment_content,
comment_author:row.comment_author
})
}
//update the id to check against the next row
lastid = row.article_id;
}
//make sure you push on the last article
table.push(article);
//Now you can send back the table in the new structure...
return table;