How to make a request to post an array to the server? - node.js

I need to execute a request to send an array. But when I do this I get null as the result.
Result Request Payload:
[
{nom_name: "Test", cost: 500, quantity: 1, parentOrder_id: 19},
{nom_name: "35634", cost: 100, quantity: 1, parentOrder_id: 19}
]
Result Preview:
{
address: null
apartment: null
code: null
cost: null
date_delivery: null
floor: null
hierarchyLevel: 1
is_new: true
name: null
nom_name: null
order_id: 40
parentOrder_id: null
payment: null
quantity: null
telephone: null
}
How do I fix to prevent null values ​​from being sent to the server for the values ​​I am sending? And so that the post request sends exactly an array, and not a single object.
service:
create(order: Order[]): Observable<Order> {
return this.http.post<Order>(`${env.url}/api/orders/create`, order);
}
ts:
onSave() {
const order: Order[] =
this.order.list.map(e => {
const { order_id, ...rest } = e
return ({ ...rest, parentOrder_id: 19 })
})
this._order.create(order)
.subscribe(
() => {
console.log('Data Saved.')
},
error => {
console.log(error)
}
);
}
On the server I am using Nodejs and ORM Sequelize.
node.js controller:
module.exports.create = function (req, res) {
const order = db.orders.bulkCreate([
{
nom_name: req.body.nom_name,
quantity: req.body.quantity,
cost: req.body.cost,
parentOrder_id: req.body.parentOrder_id
}
])
res.status(201).json(order);
};

I haven't personally worked a lot with sequelize, but I'm pretty sure that you need to pass the the request-body object directly since req.body contains the array of data and thus req.body.nom_name for example will be undefined. Also bulkCreate is defined as an async-function that you should await before sending the response:
module.exports.create = async (req, res) => {
const orders = await db.orders.bulkCreate(req.body);
res.status(201).json(orders);
};

Related

Import large amounts of data, but do a .find() for each element

I have a collection of customers of 60.000 items. I need to import a list of people, of 50.000. But for each person, I need to find the ID of the customer and add that to the object that is being inserted.
How should this be done most efficently?
export default async ({ file, user, database }: Request, res: Response) => {
try {
const csv = file.buffer.toString("utf8");
let lines = await CSV({
delimiter: "auto" // delimiter used for separating columns.
}).fromString(csv);
let count = {
noCustomer: 0,
fails: 0
};
let data: any = [];
await Promise.all(
lines.map(async (item, index) => {
try {
// Find customer
const customer = await database
.model("Customer")
.findOne({
$or: [
{ "custom.pipeID": item["Organisasjon - ID"] },
{ name: item["Person - Organisasjon"] }
]
})
.select("_id")
.lean();
// If found a customer
if (!isNil(customer?._id)) {
return data.push({
name: item["Person - Navn"],
email: item["Person - Email"],
phone: item["Person - Telefon"],
customer: customer._id,
updatedAt: item["Person - Oppdater tid"],
createdAt: item["Person - Person opprettet"],
creator: users[item["Person - Eier"]] || "5e4bca71a31da7262c3707c5"
});
}
else {
return count.noCustomer++;
}
} catch (err) {
count.fails++;
return;
}
})
);
const people = await database.model("Person").insertMany(data)
res.send("Thanks!")
} catch (err) {
console.log(err)
throw err;
}
};
My code just never sends an response If I use this as a Express request.

async await with promise all

I want to know if I am using promise.all correctly with async await.
Basically, I need to get the house data based on the ID, then I need to get all the reviews for that house as well as the count of reviews.
server.get("/api/houses/:id", async (req, res) => {
const { id } = req.params;
const house = await House.findByPk(id);
if (!house) {
return res.status(400).send("No house found");
}
const reviews = await Review.findAndCountAll({
where: {
houseId: house.id
}
});
house.dataValues.reviewsCount = reviews.count;
const results = await Promise.all([house.dataValues, reviews.rows]);
console.log(results);
res.send(results);
});
In the front end when I console.log the response after making the http request, I get back the below which seems okay since Promise.all gives you arrays. But I don't know if this is the best way to do this or if there is a better way.
[
{
id: 2329,
host: 2,
picture: '/img/houses/1.jpg',
type: 'Entire house',
town: 'Some town',
title: 'Some title',
price: 50,
description: 'Some description',
guests: 4,
bedrooms: 1,
beds: 2,
baths: 1,
wifi: true,
reviewsCount: 2
},
[
{
id: 1,
houseId: 2329,
userId: 1,
comment: 'An awesome review',
createdAt: '2019-01-11T22:00:00.000Z',
updatedAt: '2019-01-11T22:00:00.000Z'
},
{
id: 2,
houseId: 2329,
userId: 2,
comment: 'Another awesome review',
createdAt: '2019-01-11T22:00:00.000Z',
updatedAt: '2019-01-11T22:00:00.000Z'
}
]
]
You're not using Promise.all correctly. The code is working, because you're awaiting each promise individually.
Since Review.findAndCountAll depends on House.findByPk result, Promise.all won't do any good here.
You're using Promise.all with the already resolved values of the both promises, so you can just drop it.
server.get("/api/houses/:id", async (req, res) => {
const { id } = req.params;
const housePromise = await House.findByPk(id);
const reviews = await Review.findAndCountAll({
where: {
houseId: house.id
}
});
house.dataValues.reviewsCount = reviews.count;
res.send([house.dataValues, reviews.rows]);
});
Basically you're doing:
const res = await Promise.all([1, 5]); // [1, 5]
Which can be translated directly to:
const res = [1, 5];
Instead of sending it in an array, I think it's better to send an object:
{
house: house.dataValues,
reviews: reviews.rows
}
You can ignore async await and use Promise. You can try following code
server.get("/api/houses/:id", async (req, res) => {
const { id } = req.params;
return House.findByPk(id)
.then( house => {
// !house might be 'true' if house is 'undefined'
if( house === undefined || !house ) {
return res.status(400).send("No house found");
}
return Review.findAndCountAll({ where: { houseId: house.id } })
.then(reviews => {
house.dataValues.reviewsCount = reviews.count;
return {house, reviews};
})
.catch(error => res.send(error));
})
.then( result => {
return res.send(results);
})
.catch(error => {
return res.send(error);
});
})

GET request works on backend with Postman, but returns null to frontend

I have a GET request where if I add the creator to the post as a param like api/watchlist/?creator=5dac9d3567aca81e40bfc0 and test it in Postman, the results return all posts by that creator with the following code correctly.
app.js
app.get('/api/watchlist',(req, res, next)=>{
Watching.find({ creator: req.query.creator})
.then(documents => {
console.log("Creator value: " + req.query.creator);
res.status(200).json({
message: 'User\'s watchlist items retrieved!',
posts: documents
});
});
});
If I try and pull the GET request into angular, then it returns nothing.
Also the front end when I open the relevant webpage says frontend is saying ERROR TypeError: "retrievedData.posts is undefined"
getWatchListItems watch-list.service.ts:72
watch-list.service.ts
getWatchListItems(creator: string) {
this.http
.get<{ message: string; posts: any; maxPosts: number; watchlist: string }>(
"http://localhost:3000/api/watchlist?creator=" + creator
)
.pipe(
map(retrievedData => {
console.log(retrievedData.watchlist);
return {
posts: retrievedData.posts.map(post => {
console.log(retrievedData.watchlist);
return {
title: post.title,
cost: post.cost,
listingOwner: post.listingOwner,
id: post._id
};
}),
maxPosts: retrievedData .maxPosts
};
})
)
.subscribe(transformedPostData => {
console.log(transformedPostData);
this.posts = transformedPostData.posts;
this.postsUpdated.next({
listing: [...this.posts],
postCount: transformedPostData.maxPosts
});
});
}
watching.component.ts
ngOnInit() {
this.userId = localStorage.getItem("userId: ");
// this.userId = this.authService.getUserId();
this.watchListService.getWatchListItems(this.userId);
this.postsSub = this.watchListService
.getPostUpdateListener()
.subscribe((postData: { listing: Watching[]; postCount: number }) => {
this.totalPosts = postData.postCount;
this.posts = postData.listing;
});
}
You are sending the create as a route parameter in angular service.
So you need to modify your api like this:
app.get('/api/watchlist/:creater', (req, res, next) => {
Watching.find({ creator: req.params.creator })
.then(documents => {
console.log("Creator value: ", req.params.creator);
res.status(200).json({
message: 'User\'s watchlist items retrieved!',
watchlist: documents
});
});
});
And if you dont want to change the api, you should send the creator as a query param like this:
return this.http
.get<{ message: string; posts: any; maxPosts: number }>(
"http://localhost:3000/api/watchlist?creator=" + creator
)
After this, you must handle the response data in angular, and transform to your needs.
Can you update the question, by including this console.log result with this code? (as I know in the service you don't need to subscribe, you are subscribing in your component)
getWatchListItems(creator: string) {
return this.http("http://localhost:3000/api/watchlist?creator=" + creator)
.pipe(
map(retrievedData => {
console.log("retrievedData: ", retrievedData);
//todo: transform retrievedData
return retrievedData;
})
)
}
Don't forget your api returns the data in this format, so you should
{
"watchlist": ...
"message": ...
}

GraphQL with RESTful returning empty response

I am connecting GraphQL with REST endpoints, I confirmed that whenever I am calling http://localhost:3001/graphql it is hitting REST endpoint and it is returning JSON response to GraphQL server, but I am getting an empty response from GraphQL server to GUI as follows:
{
"data": {
"merchant": {
"id": null
}
}
}
Query (decoded manually):
http://localhost:3001/graphql?query={
merchant(id: 1) {
id
}
}
Below is how my GraphQLObjectType looks like:
const MerchantType = new GraphQLObjectType({
name: 'Merchant',
description: 'Merchant details',
fields : () => ({
id : {
type: GraphQLString // ,
// resolve: merchant => merchant.id
},
email: {type: GraphQLString}, // same name as field in REST response, so resolver is not requested
mobile: {type: GraphQLString}
})
});
const QueryType = new GraphQLObjectType({
name: 'Query',
description: 'The root of all... queries',
fields: () => ({
merchant: {
type: merchant.MerchantType,
args: {
id: {type: new GraphQLNonNull(GraphQLID)},
},
resolve: (root, args) => rest.fetchResponseByURL(`merchant/${args.id}/`)
},
}),
});
Response from REST endpoint (I also tried with single object in JSON instead of JSON array):
[
{
"merchant": {
"id": "1",
"email": "a#b.com",
"mobile": "1234567890"
}
}
]
REST call using node-fetch
function fetchResponseByURL(relativeURL) {
return fetch(`${config.BASE_URL}${relativeURL}`, {
method: 'GET',
headers: {
Accept: 'application/json',
}
})
.then(response => {
if (response.ok) {
return response.json();
}
})
.catch(error => { console.log('request failed', error); });
}
const rest = {
fetchResponseByURL
}
export default rest
GitHub: https://github.com/vishrantgupta/graphql
JSON endpoint (dummy): https://api.myjson.com/bins/8lwqk
Edit: Adding node.js tag, may be issue with promise object.
Your fetchResponseByURL function get empty string.
I think the main problem is that you are using wrong function to get the your JSON string, please try to install request-promise and use it to get your JSON string.
https://github.com/request/request-promise#readme
something like
var rp = require('request-promise');
function fetchResponseByURL(relativeURL) {
return rp('https://api.myjson.com/bins/8lwqk')
.then((html) => {
const data = JSON.parse(html)
return data.merchant
})
.catch((err) => console.error(err));
// .catch(error => { console.log('request failed', error); });
}
In this case using data.merchant solved my problem. But the above suggested solution i.e., use of JSON.parse(...) might not be the best practice because if there are no object in JSON, then expected response might be as follows:
{
"data": {
"merchant": null
}
}
Instead of fields to be null.
{
"data": {
"merchant": {
"id": null // even though merchant is null in JSON,
// I am getting a merchant object in response from GraphQL
}
}
}
I have updated my GitHub: https://github.com/vishrantgupta/graphql with working code.

How to update a model? .updateAttributes is not a function

I'm building a Node Express app, with Postgres as DB and Sequelize as ORM.
I have a router.js file:
router.route('/publish')
.put((...args) => controller.publish(...args));
controller.js which looks like this:
publish(req, res, next) {
helper.publish(req)
.then((published) => {
res.send({ success: true, published });
});
}
And a helper.js
publish(req) {
return new Promise((resolve, reject) => {
Article.findAll({
where: { id: req.query.article_id },
attributes: ['id', 'state']
})
.then((updateState) => {
updateState.updateAttributes({
state: 2
});
})
.then((updateState) => {
resolve(updateState);
});
});
}
So for example when I hit PUT http://localhost:8080/api/publish?article_id=3555 I should get:
{
"success": true,
"published": [
{
"id": 3555,
"state": 2
}
]
}
The current state of the article is 1.
However, I get the following error Unhandled rejection TypeError: updateState.updateAttributes is not a function. When I remove the updateState.updateAttributes part from my helper.js I get the response with the current state.
How do I update the state of the article correctly?
You should just change findAll with findOne , as you are just trying to find specific article by id :
Article.fineOne({ //<--------- Change here
where: { id: req.query.article_id },
attributes: ['id', 'state']
})
.then((updateState) => {
updateState.updateAttributes({state: 2}); //<------- And this will work
})
But if you still want to go with findAll and to know how to use that , Please try this and read the comments , that will clear all your doubts :
Article.findAll({
where: { id: req.query.article_id },
attributes: ['id', 'state']
})
.then((updateState) => {
// updateState will be the array of articles objects
updateState.forEach((article) => {
article.updateAttributes({ state: 2 });
});
//-------------- OR -----------------
updateState.forEach((article) => {
article.update({ state: 2 });
});
})

Resources