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 });
});
})
Related
I would like to order this find function through the table relation.
const [people, total] = await typePersonServiceInstance.find(
{
take,
skip,
where: (qb: any) => {
qb.where('person.type IN (:...type)', { type });
qb.andWhere('person.status IN (:...status)', { status });
if (query.search) {
qb.andWhere(new Brackets((subQb) => {
subQb.where('name like :name', { name: `%${query.search}%` });
subQb.orWhere('fantasyName like :fantasyName', { fantasyName: `%${query.search}%` });
subQb.orWhere('person.city like :city', { city: `%${query.search}%` });
subQb.orWhere('person.state like :state', { state: `%${query.search}%` });
subQb.orWhere('person.id = :id', { id: query.search });
}));
}
},
order: {
person: {
status: 'ASC'
}
}
},
);
The issue i'm facing is when trying to order by some attribute from person table, if I do
order: {
anyColumnFromTypePersonHere: 'ASC' | 'DESC'
}
It works pretty fine, but if I want to order by status (that is an attribute from person) it will not work
Just add this line:
qb.addOrderBy('person.status', "ASC") ;
I'm writing a put method in node js and i have an error when i want to save the post it shows me an error.
Post.findOne({'imei.modele': req.query.modele, test: { $exists: true } })
.then((posts) => {
console.log(posts);
posts=aa;
posts.save().then(posts=>{
res.json('bonjour');
})
})
});
I get the following error - TypeError: posts.save is not a function
The request.find works correctly and the req.body is also good
so i need some help and thank you
Hello it's obvious to have this behavior because you re-assign the value of posts with aa :
remove this
posts=aa;
Try like this
Post.findOne({'imei.modele': req.query.modele, test: { $exists: true } })
.then((posts) => {
console.log(posts);
posts.save().then(posts=>{
res.json('bonjour');
})
})
});
if you want to edit posts before save try something like this
Post.findOne({'imei.modele': req.query.modele, test: { $exists: true } })
.then((posts) => {
console.log(posts);
posts.modele = 'updated model'
posts.save().then(posts=>{
res.json('bonjour');
})
})
});
where this like posts.modele = 'updated modele' should update modele property
Cleaner way
Post.findOneAndUpdate({'imei.modele': req.query.modele, test: { $exists: true } }, { $set : { req.body } }).then(doc=>{
res.json('success');
})
I got a problem with my code.It jumps to second .then section without completing first job. After that, it goes back to first promise but never executes code inside second .then
Promise.all(jobs).then((values) => {
console.log("First!")
values.forEach(function(vals) {
vals.forEach(function(doc) {
if (doc.properties.location_i.toString() == request.body.id) {
jobs_do.push(dbo.collection("zones").find({
"geometry": {
$geoIntersects: {
$geometry: {
type: "Point",
coordinates: [
docs[values.indexOf(vals)].geometry_do.coordinates[0],
docs[values.indexOf(vals)].geometry_do.coordinates[1]
]
}
}
}
}))
}
})
})
}).then(function() {
console.log("Second!")
Promise.all(jobs_do).then((values) => {
values.forEach(function(vals) {
vals.forEach(function(doc) {
console.log(doc.properties.objectid);
});
})
});
});
It fulfills jobs_do array but Promise.all(jobs_do).then((values)) executed once when jobs_do is empty.
Console log is:
First!
Second!
Although I can't exactly replicate the setup you have above, here's a simple example that should guide you how to re-write your code so that it works as it's supposed to.
const jobs = Array.from({ length: 2 })
.map((_, idx) => {
return Promise.resolve({
id: idx + 1,
title: `Job ${idx + 1}`
})
})
const jobs_do = [];
Promise.all(jobs)
.then(values => {
console.log("first!");
for (const value of values) {
if (true) {
jobs_do.push(
Promise.resolve({
...value,
description: `This is a description for job ${value.id}`
})
);
}
}
return Promise.all(jobs_do);
})
.then(results => {
console.log("second!");
results.forEach(result => {
console.log(`[${result.id}] | ${result.title} | ${result.description}`);
});
});
I'm having a problem identifying a 'task' in mongoDB from my frontend angular.
This question is the most similar to my question but here it just says req.body.id and doesn't really explain how they got that.
This question involves what I am trying to do: update one document in a collection upon a click. What it does in the frontend isn't important. I just want to change the status text of the Task from "Active" to "Completed" onclick.
First I create a task and stick it in my database collection with this code:
createTask(): void {
const status = "Active";
const taskTree: Task = {
_id: this._id,
author: this.username,
createdBy: this.department,
intendedFor: this.taskFormGroup.value.taskDepartment,
taskName: this.taskFormGroup.value.taskName,
taskDescription: this.taskFormGroup.value.taskDescription,
expectedDuration: this.taskFormGroup.value.expectedDuration,
status: status
};
this.http.post("/api/tasks", taskTree).subscribe(res => {
this.taskData = res;
});
}
When I make this post to the backend, _id is magically filled in!
I'm just not sure how I can pass the id to the put request in nodejs router.put('/:id') when I'm pushing it from the frontend like this:
completeTask(): void {
const status = "Completed";
const taskTree: Task = {
_id: this._id,
author: this.username,
createdBy: this.department,
intendedFor: this.taskFormGroup.value.taskDepartment,
taskName: this.taskFormGroup.value.taskName,
taskDescription: this.taskFormGroup.value.taskDescription,
expectedDuration: this.taskFormGroup.value.expectedDuration,
status: status
};
console.log(taskTree);
this.http.put("/api/tasks/" + taskTree._id, taskTree).subscribe(res => {
this.taskData = res;
console.log(res);
});
}
In the template I have a form that's filled in and the data is immediately outputted to a task 'card' on the same page.
When I send the put request from angular, I get a response in the backend just fine of the response I ask for in task-routes.js:
router.put("/:id", (req, res, next) => {
const taskData = req.body;
console.log(taskData);
const task = new Task({
taskId: taskData._id,
author: taskData.author,
createdBy: taskData.createdBy,
intendedFor: taskData.intendedFor,
taskName: taskData.taskName,
taskDescription: taskData.taskDescription,
expectedDuration: taskData.expectedDuration,
status: taskData.status
})
Task.updateOne(req.params.id, {
$set: task.status
},
{
new: true
},
function(err, updatedTask) {
if (err) throw err;
console.log(updatedTask);
}
)
});
The general response I get for the updated info is:
{
author: 'there's a name here',
createdBy: 'management',
intendedFor: null,
taskName: null,
taskDescription: null,
expectedDuration: null,
status: 'Completed'
}
Now I know _id is created automatically in the database so here when I click create task & it outputs to the 'card', in the console log of task after I save() it on the post request, taskId: undefined comes up. This is all fine and dandy but I have to send a unique identifier from the frontend Task interface so when I send the 'put' request, nodejs gets the same id as was 'post'ed.
I'm quite confused at this point.
So I finally figured this out...In case it helps someone here's what finally worked:
First I moved my update function and (patch instead of put) request to my trigger service:
Trigger Service
tasks: Task[] = [];
updateTask(taskId, data): Observable<Task> {
return this.http.patch<Task>(this.host + "tasks/" + taskId, data);
}
I also created a get request in the trigger service file to find all the documents in a collection:
getTasks() {
return this.http.get<Task[]>(this.host + "tasks");
}
Angular component
Get tasks in ngOnInit to list them when the component loads:
ngOnInit() {
this.triggerService.getTasks().subscribe(
tasks => {
this.tasks = tasks as Task[];
console.log(this.tasks);
},
error => console.error(error)
);
}
Update:
completeTask(taskId, data): any {
this.triggerService.updateTask(taskId, data).subscribe(res => {
console.log(res);
});
}
Angular template (html)
<button mat-button
class="btn btn-lemon"
(click)="completeTask(task._id)"
>Complete Task</button>
// task._id comes from `*ngFor="task of tasks"`, "tasks" being the name of the array
//(or interface array) in your component file. "task" is any name you give it,
//but I think the singular form of your array is the normal practice.
Backend Routes
GET all tasks:
router.get("", (req, res, next) => {
Task.find({})
.then(tasks => {
if (tasks) {
res.status(200).json(tasks);
} else {
res.status(400).json({ message: "all tasks not found" });
}
})
.catch(error => {
response.status(500).json({
message: "Fetching tasks failed",
error: error
});
});
});
Update 1 field in specified document (status from "Active" to "Completed"):
router.patch("/:id", (req, res, next) => {
const status = "Completed";
console.log(req.params.id + " IT'S THE ID ");
Task.updateOne(
{ _id: req.params.id },
{ $set: { status: status } },
{ upsert: true }
)
.then(result => {
if (result.n > 0) {
res.status(200).json({
message: "Update successful!"
});
}
})
.catch(error => {
res.status(500).json({
message: "Failed updating the status.",
error: error
});
});
});
Hope it helps someone!
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.