MongoDB objectID stranger Error - node.js

Using a MEAN Stack deployment on Heroku I am able to GET and DELETE Documents with mongoDB's findOne and deleteOne functions. However when I try to PUT a document with the mongoDB updateOne/update function, I receive this error (server side) :
The _id field cannot be changed from {_id: ObjectId('56d4d71191fdc81100974d0b')} to {_id: "56d4d71191fdc81100974d0b"}.
Seems strange because I am using the same method in my server code for updateOne as in findOne (again, findOne works fine):
app.get("/contacts/:id", function(req, res) {
db.collection(CONTACTS_COLLECTION).findOne({ _id: new ObjectID(req.params.id) }, function(err, doc) {
if (err) {
handleError(err.message, "Failed to get contact");
} else {
res.status(200).json(doc);
}
});
});
app.put("/contacts/:id", function(req, res) {
var updateDoc = req.body;
db.collection(CONTACTS_COLLECTION).updateOne({_id: new ObjectID(req.params.id)}, updateDoc, function(err, doc) {
if (err) {
handleError(err.message, "Failed to update contact");
} else {
res.status(204).end();
}
});
});
Any suggestions?

I think you have problem at var updateDoc = req.body
As req.body contains id field and you are searching from object to update by that id, mongodb thinks you are trying to update
id field too which is not allowed.
One solution is to remove id field from your updateDoc object.
e.g.
delete updateDoc._id;
now try again and see if it works.
Your final function should look like
app.put("/contacts/:id", function(req, res) {
var updateDoc = req.body;
delete updateDoc.id;
db.collection(CONTACTS_COLLECTION).updateOne({_id: new ObjectID(req.params.id)}, updateDoc, function(err, doc) {
if (err) {
handleError(err.message, "Failed to update contact");
} else {
res.status(204).end();
}
});
});

Related

CastError: Cast to ObjectId failed for value " 60f0d02f36ee6f2e505369e8" (type string) at path "_id" for model "collection"

app.get("/posts/:postId", function (req, res) {
let requestedPostId = req.params.postId;
Post.findById(requestedPostId, function (err, post) {
if (!err) {
res.render("post", { postTitle:post.title, postBody:post.content });
} else {
console.log(err);
}
});
});
This is the error I'm getting:
When I tried putting the existing _id of the document from the database in '''requestedPostId variable''' , then the code is working fine and the page gets loaded perfectly.
I mean to say that the database is not able to fetch data due to some casting error of objectId.
Can someone help?
Thanks in advance.
There's a Space in the ID being added, You can remove it, or add the trim function before doing the update.
app.get("/posts/:postId", function (req, res) {
let requestedPostId = (req.params.postId).trim();
Post.findById(requestedPostId, function (err, post) {
if (!err) {
res.render("post", { postTitle:post.title, postBody:post.content });
} else {
console.log(err);
}
});
});

How to check if a document exisits in MongoDB

I am trying to check if a document exists in MongoDB and then based on that either update the document or create a new one. However only the if statement is being recorded. I have checked that the value of documentExists is null if no document is in mongo.
router.post("/mongo", async function (req, res) {
const documentExists = await Files.findOne({
_id: req.body.id,
});
if (documentExists) {
try {
Files.updateOne(
{ _id: documentExist._id },
{ flag: req.body.flag },
function (err, result) {
if (err) {
res.send(err);
} else {
res.send(result);
}
}
);
} catch (err) {
res.status(400).send(err);
}
} else {
CREATE NEW DOCUMENT
}
})
In your case you can use findOneAndUpdate to update if there is any existing document in the collection, if there is no matching document the query returns null.

MongoDb delete documents by passing user id

I am new to node and mongo db. I have a list of users with delete link in each row.I am trying to delete a user with its _id. However its not working.
Here is my router code.
router.get('/delete/:id', function (req,res) {
const ObjectId = require('mongodb').ObjectID;
var id = req.params.id;
console.log(id);
db.collection('users').deleteOne({ _id: ObjectId(req.params.id) }, function(err, res) {
if (err) {
throw err;
} else {
return res.redirect('/');
}
});
});
Here is my view, on clicking this link I am getting the _id in my url as this : http://localhost:3000/delete/4428439e14e3343ba4ac31c1
<td>Delete</td>
console.log(id) gives me 4428439e14e3343ba4ac31c1
But it throws me the below error
Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters
at new ObjectID
Try this, you don't need to create ObjectID if the string is a valid ObjectID
For prevention, you can use a function like below to test if valid ObjectID is passed or not
function validateObjectId (id) {
if (ObjectId.isValid(id)) {
const obj = new ObjectId(id);
if (obj == id) {
return true;
}
}
return false;
},
if(!validateObjectId(req.params.id))
return res.send({'error':'Invalid ObjectID Passed',id:req.params.id});
db.collection('users').deleteOne({ _id: ObjectId(req.params.id) }, function(err, res)
{
if (err) {
throw err;
} else {
return res.redirect('/');
}
});
Also remove extra space from here
<td>Delete</td>
You need to create a instance of ObjectId using new. Currently, you are passing the ObjectId directly so you are getting that error.
db.collection('users').deleteOne({_id: new ObjectId(req.params.id)}, function(err, res) {
if (err) {
throw err;
} else {
return res.redirect('/');
}
});
you can use findByIdAndRemove
router.get('/delete/:id', function (req,res) {
var id = req.params.id;
db.collection('users').findByIdAndRemove( id , function(err, res) {
if (err) {
throw err;
} else {
return res.redirect('/');
}
});
});
Maybe you can try this code below:
router.get("/delete/:id", function(req, res) {
const ObjectId = require("mongodb").ObjectId;
var { id } = req.params;
console.log(id);
db.collection("users").findOneAndDelete({ _id: ObjectId(id) }, function(
error,
response
) {
if (error) {
throw err;
} else {
return res.redirect("/");
}
});
});
Updated:
Try looking at your code. There's confusing code, you use 2 times res. One is res from express and the other isres when it succeeds in removing at mongodb.
So, the res.redirect ('/') that you use in your mongodb function is res from mongodb, notres from express.
Try replacing {err, res} with {error, response}.
I hope it can help you.

NodeJS & MongoDB - Get Objects based on array of ids

I am having trouble returning getting the Objects in a collection based on an array of ObjectIds.
I have a collection of 10 items. In an iOS app, I am passing up an array of ObjectIds that user has saved as favorites to return just those two in a favorites tab, for example -
["59f85eae4545XXX9b94d53d3", "59f85eae45454XXXb94d76a1"]
For now, I have just hardcoded the ObjectIds at the top of the request using NodeJS just until I get the request working, below is the request -
exports.list_favs = function(req, res) {
Articles.find({
_id: { $in: [
mongoose.Types.ObjectId('59f85aXXXXf1769b94d53ce'),
mongoose.Types.ObjectId('59f85eaeXXXX1769b94d53d3')
]}
}, function(err, articles) {
if (err)
res.send(err);
res.json({
data: {
articles
}
});
});
};
And I have even tried this -
exports.list_favs = function(req, res) {
var ids = new Array( new ObjectId("59f85eaeXXXX1769b94d53d3"), new
ObjectId("59f85aXXXXf1769b94d53ce") );
Articles.find({
_id: { $in: ids}
}, function(err, articles) {
if (err)
res.send(err);
res.json({
data: {
articles
}
});
});
};
Both these give me an error "CastError"
"Cast to ObjectId failed for value \"favourites\" at path \"_id\" for model \"Articles\""
This is how it looks in the database so I am completely baffled as to what I am doing wrong. Image of ObjectId in database
I've followed multiple other answers on StackOverflow with no luck.
Gist to full project code
Do this way :
exports.list_favs = function(req, res) {
Articles.find({
_id: {
$in: [mongoose.Schema.ObjectId('59f85aXXXXf1769b94d53ce'),
mongoose.Schema.ObjectId('59f85eaeXXXX1769b94d53d3')]
}
},
function(err, articles) {
if (err)
res.send(err);
else
res.json({
data: {
articles
}
});
});
};

Mongoose change document _id on save/update

a quick one:
Why is Mongoose change/upgrading the _id field of a document when I push an update?
Is this an intended behavior?
Thanks.
This is the update I use inside my PUT route, and it returns successfully the updated model, but unfortunately with a new _id for doc
Document.findById(req.params.doc_id, function (err, doc) {
if (err)
res.send(err)
// Do some subdoc stuff here …
doc.save(function (err) {
if (!err) {
console.log('Success!');
res.json(doc);
} else {
console.log(err);
}
});
});
Okay, problem solved:
I was logging the wrong _id (doh!)
Mongoose docs http://mongoosejs.com/docs/2.7.x/docs/model-definition.html
suggest using update or findOne
ex:
var query = { name: 'borne' };
Document.update({"_id": req.params.doc_id}, { name: 'jason borne' }, {}, function(err, numAffected){
if (!err) {
console.log('Success!');
res.json(numAffected);
} else {
console.log(err);
}
});
or
Model.findOne({ "_id": req.params.doc_id }, function (err, doc){
doc.name = 'jason borne';
doc.save();
// here you could use your save instead, but try not to use the doc again
// it is confusing
// doc.save(function (err, documentSaved, numberAffected) {
// if (!err) {
// console.log('Success!');
// res.json(documentSaved);
// } else {
// console.log(err);
// }
// });
});
Later I also found the findById update suggested in some docs http://mongoosejs.com/docs/documents.html, which seems to be up to date, check the version you are using and also double check the two times you are using doc in your functions here. Also you can check your mongoDB and see if there are more than one record getting saved.
db.documents.find( {} )

Resources