Node.js - Como fazer uma rota post para o registro de uma array de objetos?

Vitor Alecrim
5 min readFeb 7, 2023

A intenção deste artigo é te ensinar como manipular uma array de objetos em uma rota post feita em nodejs e mysql.

Olá à todos,

Espero que este artigo te encontre bem e, sem mais delongas, vamos direto ao ponto.

Caso você queira saber como criar um pequeno servidor usando Node.js e Mysql clique aqui.

Recentemente estou trabalhando em um aplicativo para entregas e ocorreu-me de lidar com um problema que nunca tive antes. Como eu registro em meu banco de dados uma array de objetos relacionados?

A minha primeira idéia foi simplesmente criar um for onde a cada key da array eu registraria os valores do objeto, porém isso causava um erro na resposta do node.js que até agora, admito, não compreendo o por quê de ocorrer.

Durante este tutorial irei usar algumas imagens exemplificando supostos casos que você terá de arrays de objetos, sinta-se livre para fazer a modificação que quiser.

No mais, vamos direto ao código.

Primeiro Passo

Crie uma tabela em seu database onde será salvo a array de objetos. A minha está assim. Sinta-se livre para modifica-la como bem entender.

create table orders(
id int NOT NULL AUTO_INCREMENT,
uuid varchar(200) NOT NULL,
storeId int NOT NULL,
product JSON DEFAULT NULL,
quantity integer,
price DECIMAL(10,2) DEFAULT 0.00
);

Peço que presta atenção em dois valores desta tabela.

  • O primeiro sendo storeId. Isto será usado para relacionar a ordem do produto com a loja para qual será enviado.
  • Segundo, product JSON DEFAULT NULL, onde será salvo o produto(objeto) product oriundo de outra tabela, relacionando de forma prática as duas tabelas na chamada do sistema.

ps: não sou especialista em sql, sinta-se livre para comentar abaixo a respeito desta parte.

Uma vez criada a tabela, ela se apresentará assim no MYSQL.

MariaDB [foodstore]> show columns from orders;
+----------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| uuid | varchar(200) | NO | | NULL | |
| storeId | int(11) | NO | | NULL | |
| product | longtext | YES | | NULL | |
| quantity | int(11) | YES | | NULL | |
| price | decimal(10,2) | YES | | 0.00 | |
+----------+---------------+------+-----+---------+----------------+

Caso queira saber mais sobre Mysql clique aqui.

Uma vez estabelecida a tabela, passamos para a array de objetos.

O objeto:

A array de objetos que iremos salvar na rota será similar a esta, lembrando que em uma situação real a array será enviada pelo usuário através do frontend de sua aplicação.


const list = [
{
id:"3845bf3c-a7b0-476d-8a96-c467b7a4a5b7",
price:2.5,
quantity:3.5,
product:{
storeId:1,
storeName:"Bbq",
id:1,
categoryId:1,
description:"a delicious product"
discoutnValue:null,
price:0.50,
productImage:....
}
},
{
id:"3845bf3c-a7b0-476d-8a96-c467b7a4a5b7",
price:2.5,
quantity:3.5,
product:{
storeId:1,
storeName:"Bbq",
id:1,
categoryId:1,
description:"a delicious product"
discoutnValue:null,
price:0.50,
productImage:....
}
}
....
]

Você pode repetir quantas vezes quiser o objeto dentro da array. Por questão de exemplo, fiz apenas duas vezes.

e agora, a rota.

Criação da Rota

Para salvarmos algo no banco de dados usamos a rota post.

Primeiro irei te mostrar como eu criei a primeira rota, que me trouxe tanta dor de cabeça, e qual o erro que eu recebia do backend:

router.post("/send", (req, res, next)=>{
const orderDetails = req.body.list;
const query = "insert into orders (uuid, storeId, product, quantity, price) values(?,?,?,?,?)";
....
});

O código acima pode ser dividido em duas partes.

Primeiro crie uma constante para requesitar os dados enviados pelo frontend: const ordeDetails = req.body.list, lembrando que list neste caso se refere à array de objetos.

Depois, crie a query que irá inserir os dados em seu bancos de dados, neste caso MYSQL.

const query = "insert into insert into orders (uuid, storeId, product, quantity, price) values(?,?,?,?,?)

Caso tenha interesse em saber mais sobre a escrita de query.

Agora eu tenho minha query e minha array de objetos, porém como inserir este valor no banco de dados? Se você usar apenas o connection para a realização da chamada, haverá um erro porque você está enviando uma array e o mysql não está esperando por isso. Portanto ele não saberá o que fazer e irá te retornar um erro. Como eu disse acima, a saída então seria a criação de um for e para cada key você passaria os valores requisitados pela query.

ficando assim:

router.post("/send", (req, res, next)=>{
const orderDetails = req.body.list;
const query = "insert into orders (uuid, storeId, product, quantity, price) values(?,?,?,?,?)";

for(let key in orderDetails){
const productDetail = JSON.stringify(orderDetails[key].product)

connection.query(query, [orderDetails[key].id, orderDetails[key].product.storeId,productDetail, orderDetails[key].quantity, orderDetails[key].price], (err, result)=>{

if(!err){

return res.status(200).json({message: "Order addded successfully"});
}
else
return res.status(500).json(err);

});
}

});

Desta forma o código irá funcionar, injetando cada objeto dentro da array e os seus respectivos valores dentro do banco de dados. Porém, desta forma, irá ocorrer um erro.

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

O motivo deste erro é porquê o nodejs compreende que você está realizando mais do que um res.json, um retorno dentro de um retorno, e assim ele quebra o sistema. Se você retirar o retorno res o código continua a funcionar, porém o frontend não será avisado do sucesso de sua ação. E então, o que fazer?

Se você está até aqui, parabéns. Desculpe pela demora, mas agora vamos direto ao ponto. Como realizar uma rota post para uma array de objetos em node.js e mysql?

Mudaremos apenas um pouco do código acima e a rota irá funcionar. Uma delas é retirar o for e substitui-lo por um map que irá retornar uma array com os valores requisitados pela query.

router.post("/send", (req, res, next)=>{
const orderDetails = req.body.list.map((item)=>[
item.id,
item.product.storeId,
JSON.stringify(item.product),
item.quantity,
item.price
])
....
}

Lembre-se de usar o JSON.stringifi() para transformar o objeto product em uma string. O mysql apenas compreende string.

Por fim, modificando a query para:

const query = "insert into orders (uuid, storeId, product, quantity, price) values ?";

É necessário a retirada do `()` porque a biblioteca de conexão com o Mysql está transformando a nossa array de objetos em uma tupla. Recebendo apenas um valor ? o Mysql irá olhar dentro dele e encontrará cada um dos valores necessários para realizar a sua ação.

De resto o código ficará assim.

router.post("/send", (req, res, next)=>{
const orderDetails = req.body.list.map((item)=>[
item.id,
item.product.storeId,
JSON.stringify(item.product),
item.quantity,
item.price
]);

const query = "insert into orders (uuid, storeId, product, quantity, price) values ?";

connection.query(query, [orderDetails],(err, result)=>{
if(!err){
return res.status(200).json({message:"it' work!"})
} else
return res.status(500).json(err);
})

});

Agora seu código irá rodar sem problemas.

Espero ter ajudado

Bom código. ;)

https://twitter.com/vitoralecrim

--

--