MongoDB Error: Cannot use retryable writes with limit=0 - node.js

I'm currently working on my first node.js rest api with express, mongodb (atlas cloud) and mongoose, when i try to make a .remove request i get this error:
{
"error": {
"name": "MongoError",
"message": "Cannot use (or request) retryable writes with limit=0",
"driver": true,
"index": 0,
"code": 72,
"errmsg": "Cannot use (or request) retryable writes with limit=0"
}
This is my request:
router.delete('/:productId', (req, res, next) => {
const id = req.params.productId;
Product.remove({ _id: id })
.exec()
.then(result => {
res.status(200).json(result);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
})
}); ;
});

The findOneAndRemove() function would work more accordingly since its specific to the filtering method passed in the function .findOneAndRemove(filter, options) to remove the filtered object. Still, if the remove process is interrupted by the connection the retryRewrites=true will attempt the execution of the function when connected.
More information here
When using retryRewrites set to true tells the MongoDB to retry the same process again which in fact can help prevent failed connections to the database and operate correctly, so having it turn on is recommended.
More info here
If you are using Mongoose 5^ and MongoDB 3.6 your code is better written like:
mongoose.connect('mongodb.....mongodb.net/test?retryWrites=true', (err) => {
if(err){
console.log("Could not connect to MongoDB (DATA CENTER) ");
}else{
console.log("DATA CENTER - Connected")
}
});// CONNECTING TO MONGODB v. 3.6
router.delete('/:productId', (req, res, next) => {
const id = req.params.productId;
Product.findOneAndRemove({ _id: id })//updated function from .remove()
.exec()
.then(result => {
res.status(200).json({
message: "Product Removed Successfuly"
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
})
}); ;
});

I just changed the true to false in retryWrites=true and it worked. Is that a good approach? Or there is a better way to solve this problem?

retryWrites=true is a good thing, a workaround for this incompatibility is to use findOneAndRemove instead of remove (looks like you're using mongoose)

Related

Node GET by ID API

I have follow the instructions to create a NODE API here.
I'm trying to have a few endpoints with a NODE app to serve data to my React UI.
The database is mongodb where I have a collection for 'stores'.
I have 2 GET calls:
One to retrieve all stores
One to retrieve a store by ID
Node app.js:
app.get('/viewstores', (request, response) => {
storesCollection.find({}).toArray((error, result) => {
if (error) {
return response.status(500).send(error);
}
response.send(result);
});
});
app.get("/viewstores/:id", (request, response) => {
storesCollection.findOne({ "_id": new ObjectId(request.params.id) }, (error, result) => {
if(error) {
return response.status(500).send(error);
}
response.send(result);
});
});
I make my API calls from axios in React.
If I make a call to the first API to retrieve all stores, there no problem at all, but if I try to make the API call by ID, I still get all stores from the first API.
It seems that I am not able to target the GET by ID api.
React app
React.useEffect(() => {
axios.get('http://localhost:5000/viewstores', {
params: { _id: params.storesid}
})
.then(({data}) => {
console.log("DATA ==> ", data)
})
.catch(error => console.log("ERROR API GET ==> ", error))
}, [])
MongoDB store sample:
_id: ObjectId("12345")
businessname:"ABC"
businessaddress:"address abc 1"
Any idea why when I try to call the GET by ID I always get back the whole collection?
Thanks in advance.
Joe.
Assume params.storesid is 12345,
your current React code sends requests to http://localhost:5000/viewstores?_id=12345, and the route /viewstores is reached. To reach the /viewstores/:id route, the URL should be something likes http://localhost:5000/viewstores/12345 then Express will capture the 12345 part in the URL to request.params.id. You can try the code below:
React.useEffect(() => {
axios.get(`http://localhost:5000/viewstores/${params.storesid}`)
.then(({data}) => {
console.log("DATA ==> ", data)
})
.catch(error => console.log("ERROR API GET ==> ", error))
}, [])
You can read about Express route parameters in the official document.

Nodejs/Mongoose fetch individual data with routes. [MongoDB]

Im trying to find the cleartext for a certain hash with making a get including the hash in the link.
This code only fetches the data from the given id
router.get('/:id', async (req, res) => {
try {
const md5 = await MD5.findById(req.params.id)
res.json(md5);
} catch (err){
res.status(500).json({ message: err.message })
}
})
GET Request
http://localhost:3000/md5/5ecd8e223ec4a031bccb299b
Output
{"cleartext":"softking","hash":"1e055704bb253ab362b3563902e88fe8","_id":"5ecd8e223ec4a031bccb299b"}
My goal is to make a get request with a hash to find the cleartext instead of requesting with a id. Sorry that I can't explain better, Im a newbie in this.
First you need to pass the hash as a parameter to your get request. Then, you can use find method instead of findById provided by mongoose
router.get('/:hash', async (req, res) => {
try {
const md5 = await MD5.find({hash:req.params.hash});
res.json(md5);
} catch (err){
res.status(500).json({ message: err.message });
}
});

Express not sending response once bulk insert is complete

Implementing bulk insert in mongodb using mongoose.
The data is successfully getting saved in DB but the express is not sending the response back.
Tried it using insertMany also tried bulkWrite
try {
await Collection.insertMany(docsToBeInserted);
console.log("Insert Successful");
res.status(200).send('ok');
} catch(err) {
res.status(500).json({err})
}
Insert Successful is getting print and all the documents are successfully inserted in database but in client the call never completes after some time the call fails throwing ERR_EMPTY_RESPONSE
I usually handle this specific case in this way:
return Collection.insertMany(docsToBeInserted)
.then(res => {
res.status(200).send('ok');
})
.catch(err => {
res.status(500).json({ err })
});
I have removed async-await and leveraged Promise returned by insertMany into sending the apt response according to your sample code.
You can also replace res.status(200).send('ok') with res.send('ok') as Express will set Http status to 200.
I would recommend adding console.error(err) statement to your error handling on the code for the stack trace.
You can store the result of insertMany into a variable, and send it as response like this:
try {
const response = await Collection.insertMany(docsToBeInserted);
console.log("Insert Successful");
return res.status(200).send(response.data);
} catch (err) {
return res.status(500).json({ err })
}

Client side can't fetch server response

The Problem
I deployed a create-react-app webapp to aws ec2. It's used to display data from a database and send data to it. I use ExpressJS, CORS and MySQL.
With the following code i fetch the corresponding URL and the server.js sends back the database content. Until here, everything works fine.
getBets = _ => {
fetch("http://ec2***.amazonaws.com
.then(response => response.json())
.then(response => this.setState({bets: response.data}))
.catch(err => console.error(err))
};
The problem begins when sending data to the database with the following code:
addBet = _ => {
const { bet } = this.state;
fetch(`http://ec2***.amazonaws.com/bets/add?name=${bet.person_name}&bet=${bet.time_bet}`)
.then(response => response.json())
.then(this.getBets)
.catch(err => console.error(err))
};
On click the addBet-function populates the db, but in chrome I following error:
GET http://ec2***.amazonaws.com/bets/add?name=Peter%20Pan5&bet=10:17%205 net::ERR_EMPTY_RESPONSE
and
TypeError: Failed to fetch
Regarding chrome dev-tools, the first error corresponds to the fetch in the addBet function and the second error to the catch part.
On the server side I've the following code for processing the fetch:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES("${name}", "${bet}", CURTIME())`;
connection.query(INSERT_BET, (err, res) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I want to mention, that the res paramter in the app.get part is unused. That tells me my IDE.
After a lot of hours digging deeper in the topics of expressJS and the fetch api, I guess, that the app.get part doesn't send a response to the server. But the fetch need some response.
My Question
How do I have to change the code in the app.get part to send a proper response back to the server?
AND
Am I right with my guess?
In MYSQL when you do an insert query you get back err,results and fields in the callback function like this:
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function (error,
results, fields) {
if (error) throw error;
console.log(results.insertId);
});
You have used the parameter res for result and then you have used res.send() which now corresponds to that res parameter in the callback function and not the res object.Rewrite it like this:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES(?,?,?)`;
connection.query(INSERT_BET,[name,bet,CURTIME()] ,(err, result) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I have also used prepared statement in place of normal sql queries. These are used to prevent sql injections. I hope it will work now.

Noob - API getting stuck in a simple GET (express,node)

In trying to build my first express API, I am encountering many problems. I am following some simple guide on youtube, and his code works (FOR HIM). When I try it with Postman, I simply get nothing, but it appears to be in some kind of loop (because I handle the errors)
I have checked that my route is ok, and tried experimenting with next() (which seems like I don't need it just yet)
Player is my model made with Mongoose
app.get("/players/:id", (req, res) => {
const id = req.params.id;
Player.findById(id)
.exec()
.then(doc => {
console.log("From database", doc);
if (doc) {
res.status(200).json(doc);
} else {
res
.status(404)
.json({ message: "No valid entry found for provided ID" });
}
})
.catch(err => {
console.log(err);
res.status(500).json({ error: err });
});
});
So when trying a GET in Postman on:
http://localhost:3000/players/5cf66338f00c424494316eb2
I get a loading screen, and after some time "There was an error connecting to...".
Any help/tips/solution/insights are appreciated!
If your repo is up-to-date, then you are not connecting your app with your database.
Add the following code in your app replacing the database with your own database:
mongoose.connect('mongodb://localhost:27017/database', {useNewUrlParser: true});

Resources