User not updating in mongo after save? - javascript

I have an app for todos. I'm trying to update a specific todo within an array of todos stored in the User I'm currently logged into. This is the code that does that:
User.findById(req.user._id)
.then(user => {
user.todos.forEach(function(todo) {
if (todo._id == req.params.todoId) {
todo.completed = !todo.completed;
console.log(todo.completed);
}
})
return user.save();
})
.then(result => {
console.log(result);
res.json(result);
})
.catch(function(err) {
res.send(err);
})
When I console.log the result, everything comes out fine. When I console log the updated Todo in the ajax call I'm making in my javascript file, everything appears fine. The todo is updated. However, when I stop my server and find the user in Mongo, the todo still isn't updated.
Any help is much appreciated.

When you modify a nested property on a document, mongoose may not be aware that anything changed, so it won't know to persist the changes in the DB (otherwise it would have to pass everything, which could become expensive if you have a large document but only a tiny part of it changed).
This can be done via the markModified method:
user.todos.forEach(function(todo) {
if (todo._id == req.params.todoId) {
todo.completed = !todo.completed;
console.log(todo.completed);
}
})
user.markModified('todos');
return user.save();

Instead of doing it in JavaScript code I will suggest you can do it in query only which will more effective.
db.getCollection('User').update({"_id":<req.user._id>,"todo._id":<req.params.todoId>},
{$set:
{'todo.$.completed': true}
}, {
new : true
}
)
In this query you need to pass completed status as well.

Related

Node: run 2 sql queries at the same time

I have a simple api to communicate with my mobile app and i have some updates to do.
I want to make 2 updates at the same function (or th same route) but i dont know if its possible.
Here is the dboperation part:
async function updateCusto() {
try {
let pool = await sql.connect(config);
let updateCusto = await pool.request()
.input('input_parameter1', sql.Int, CodOS)
.input('input_parameter2', sql.Int, CodProduto)
.query("update osproduto set custounit=produto.precocusto, valorunitario=produto.precosugerido from OSProduto INNER JOIN Produto ON OSProduto.CodProduto = Produto.Codigo where codproduto=#input_parameter2 and codos=#input_parameter1")
.query("Update OSProduto set sub=qtde*valorunitario where codos=#input_parameter1") //the second one, doenst work
return updateCusto.recordsets;
}
catch (error) {
console.log(error);
throw error;
}
}
and here is the route part:
router.route("/updateCusto").post((request, response) => {
CodOS = request.body.CodOs;
CodProduto = request.body.CodProduto;
dboperations.updateCusto(CodOS, CodProduto).then(result => {
console.log(result);
response.json("Update ok!");
})
.catch(error => response.json({ error }))
})
How can i do this? Is there a way to run the 2 updates on the same operation? Or do i need to create another operation to use on the same route, after the first update is made (and if so, how can i do that?).
It's definitely possible, in fact I would do it as a transaction, this way if one of the queries fails a rollback would be made in order to preserve the state of your database.
Here are my suggestions:
Read about database transactions
Replace pure SQL with an ORM such as Sequelize or KnexJS, it will help you to prevent errors by making queries calling methods such as await OsProduto.update({ where: { id: 0 }}, newData);

PreventDefault inside of promise in React

I'm new to full stack development and I was looking for some pointers to how I can handle errors that return from a promise.
Basically, I have Game IDs stored in a MongoDB collection. When a user enters a Game ID, I want to check if the Game ID exists in the collection. If it doesn't, I don't want to link the user to a new page. If it does, the user should go to a new page.
Currently, my code doesn't prevent default and the user still goes to the "waitpage", even if I use event.preventDefault. I'm wondering how I can stop the user from going to this page.
This is the code I have right now in the frontend.
const onJoinGame = (event) => {
event.persist()
axios.get(`${BACKENDLINK}/rooms/${gameId}/room_available`)
.then((res) => {
if(res.data.Status == true){
axios.put(`${BACKENDLINK}/rooms/${gameId}/add_user`,
{
username: username
})
}
})
.catch((error) => {
event.preventDefault()
setErrorGameId("That game doesn't exist!")
})
}
And in the return statement, I use this function like so.
<Link to={`/${gameId}/waitpage`} onClick={(event) => onJoinGame(event)}>
<button className = "submit" id="joinGame">Join Game</button>
</Link>
In the backend, this is what my get function returns.
const roomAvailable = (req, res) => {
Room.findOne({roomId: req.params.id}, (err, result) =>{
if(!result){
res.status(400).json('Error: ' + err)
}
else{
res.json({'Status': true})
}
})
}
Any help would be greatly appreciated!
You can't prevent the event from a promise, you'll need to do that synchronously in the event handler.
If you do need to navigate to the other page after all, you'll have to do that manually using the imperative API of the router package (which provides Link) you're using.

firebase update on form submit not working?

Trying to submit an update to a firebase document - keep getting errors stating that the document ID isn't available. Unsure how to fix the problem exactly.
The firebase call is this,
exports.updateWorkflow = (req, res) => {
let Workflow = req.body;
db.doc(`/Workflow/${req.params.WorkflowId}`)
.update(Workflow)
.then(() => {
return res.json({ message: "Details added successfully" });
})
.catch(err => {
console.error(err);
return res.status(500).json({ error: err.code });
});
};
Route is,
app.post('/updateWorkflow', updateWorkflow);
And using postman i'm submitting
http://localhost:5000/xx/xx/api/updateWorkflow/3ejAQxPoJ6Wsqsby01S6
With a json body of
{
"claimEoT" : "false"
}
{ Error: 5 NOT_FOUND: No document to update: ...../Workflow/undefined
> at Object.callErrorFromStatus (....
> code: 5,
> details: 'No document to update: p.......',
> metadata: Metadata { internalRepr: Map {}, options: {} } }
I am trying to make it so I can update the data in the document. It is being used in a wizard form to save state, so basically when I change a variable in the form from true to false, the state changes, and when I click submit, the changes are updates in the document on firebase.
I think it's something to do with how I am creating the firebase call - or something to do with the information I am sending to the call. Very confused - feel like it should be working really
Needed to change url to include ../:workflowId

Increment field user.entries when I hit submit

any idea how to increment a field called 'entries' by 1 every time I hit the submit button and save it to the database (I am using MongoDB/mongoose)?
app.put('/image', (req, res) => {
const { id } = req.body;
User.findByIdAndUpdate(id)
.then(user => {
return res.json(user.entries);
})
.catch(err => {
res.status(400).json('Error getting entries');
console.log(err);
})
});
I tried the auto-incremet plugin, but I don't know if it works in this case, if so I couldn't quite place it in the right place. I also tried to add like
User.findByIdAndUpdate(id, {$inc: {'entries': 1}} but it only starts to work when I hit the but twice and on.
If anyone can help me It'd be a great help!! Thanks
It is working. The only reason is that, findByIdAndUpdate returns the document before actually performing the update operation. If you want to get the increment value after the update operation, You might want to split the findByIdAndUpdate and try
User.update({_id: id},{$inc: {'entries': 1}}).then(() => {
User.findOne({_id: id}).then( user =>{
return res.json(user.entries);
})
}).catch(err => {
res.status(400).json('Error getting entries');
console.log(err);
})
You could also check this solution out by #Jonathan Lonowski if you still want to go with the findByIdAndUpdate.

How to stop AngularFire2 function?

I am using AngularFire2 Authentication. All is working fine. Now what I wanted to achieve is, check it user is already in the userlist, then just update lastLogin the next time the facebook login button is clicked.
Else create a new user.
This works fine. But I can't get to stop the updateLogin() / _addUser() function to stop after updating the database.
It just keeps going. (89...)auth.service.ts:98 successfully logged in!
Here is the updateLogin()
private _updateLogIn(thisurl, data) {
return thisurl.update({
lastLogIn: firebase.database.ServerValue.TIMESTAMP,
avatar: data.photoURL
}).then((success) => {
console.log("successfully logged in!");
}); ;
}
I call this with the authentication() function as follow:
login(provider: string) {
this.af.auth.login({
provider: this._getProvider(provider)
}).then(
(success) => {
this.authenticate(success);
})
return;
}
authenticate(user: any): any {
if(!user) {
return {};
} else {
let data = user.auth.providerData[0];
this.api_url = this.af.database.object(`${this.path}/${user.auth.uid}`);
this._isUsers().subscribe(value => {
var filtered = value.filter(function(item) {
return item.uid === user.auth.uid;
});
if(filtered.length > 0){this._updateLogIn(this.api_url, data); return; }
else{ this._addUser(this.api_url, user, data); return;
}
});
return;
}
}
_isUsers(){
return this.usersList.map(snapshot => {
return snapshot;
});
}
private _addUser(thisurl, user, data){
return thisurl.set({
name: data.displayName,
username: data.displayName.replace(/ /g,"."),
avatar: data.photoURL,
email: data.email,
provider: data.providerId,
uid: user.auth.uid,
lastLogIn: firebase.database.ServerValue.TIMESTAMP
}).then((success) => {
console.log("successfully signed up!");
return;
});
}
How I stop the function execution to just once?
This basically hacks my browser tab.
(89...)auth.service.ts:98 successfully logged in!
The problem is most like related to the observable returned by _isUsers(). Although it's not clear from the question's code, it seems likely that the this.usersList returned by that function is an AngularFire2 list of all users.
AngularFire2 list and object observables emit data whenever the database changes, so it's likely that your setting the user data in _updateLogIn results in another list of users being emitted, etc.
To solve the problem, you could use the first operator:
import 'rxjs/add/operator/first';
this._isUsers().first().subscribe(...)
However, it's not clear why you need to subscribe to that observable in the first place. You might want to consider refactoring the code in your question, as it seems overly complicated.
It's generally a good idea to avoid as many subscribe calls as possible. You might want to read RxJS: Don’t Unsubscribe.

Categories

Resources