How to check if a document exisits in MongoDB - node.js

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.

Related

find and modify obejct in mlab collection by _id with nodejs

i am posting an object to update the current one. Searching by id and replacing it. For some reason i don't get errors but the mlab object is not updated. Am i missing something?
app.post("/api/updateCheck", function (req, res) {
console.log('updating', req.body);
conn.collection("checks").findAndModify({
_id: req.body._id
}, {$set: req.body}, {}, function(err,doc) {
if (err) { console.log(err) }
else { console.log("Updated"); }
});
});
got it. updateOne seems to work. I am posting a check object and retrieving id from it to search the collection and update content accordingly.
// modify content
app.post("api/updateCheck", function(req, res) {
console.log("updating", req.body);
conn.collection("checks").updateOne(
{
_id: new ObjectId(req.body._id)
},
{
$set: {
content: req.body.content
}
},
function(err, doc) {
if (err) {
console.log("error", err);
} else {
console.log('success', doc.modifiedCount);
console.log('??', doc.matchedCounted);
res.status(200).json(res.body);
}
}
);
});

MongoDB objectID stranger Error

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();
}
});
});

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( {} )

Avoid extra query with Mongo and Express in PUT

I'm updating a record in Mongo with Mongoose/Express:
app.put('/loggedIn/:id', function(req, res) {
if (req.user._id == req.params.id) {
User.update({
_id: req.user._id
}, {
$set: {
interests: req.body.interests
}
}, function(err, num) {
if (err) return err;
User.findById(req.user._id, '_id username interests', function(err, user) {
if (err) return;
res.json(user);
});
});
} else {
console.log('fail');
}
});
How can I avoid doing the second query in the callback of the update(), seems a lot just to return the newly updated document.
If you're always updating only one document you can use findByIdAndUpdate (or findOneAndUpdate), which updates the document if found and returns it to the callback:
app.put('/loggedIn/:id', function(req, res) {
if (req.user._id == req.params.id) {
User.findByIdAndUpdate(req.user._id, {
$set: {
interests: req.body.interests
}
}, function(err, user) {
if (err) return;
res.json(user);
});
} else {
console.log('fail');
}
});
I think you can get the raw Mongo response as the 3rd update callback argument. Check if this contains what you want. Otherwise, try passing the option { raw: true }.
See http://mongodb.github.io/node-mongodb-native/markdown-docs/insert.html
You could use findByIdAndUpdate instead of a separate find and update.
I also sometimes do User.Find() and then inside the success callback Doc.save(). That lets you do more complex things between if it's not just a straight update from the request.

Update a record where _id = :id with Mongoose

I'm trying to update an existing record with Mongoose. The insert is OK but not the update.
Here is my snippet:
app.post('/submit', function(req, res) {
var my_visit = new models.visits({
date: req.body.visit_date,
type: req.body.visit_type,
agency: req.body.visit_agency,
city: req.body.visit_city,
url: req.body.visit_url,
note: req.body.visit_note
});
// INSERT
if(req.body.id == 0) {
my_visit.save(function(err) {
if(err) { throw err; }
console.log('added visit');
res.redirect('/');
});
} else { // UPDATE
var upsertData = my_visit.toObject();
console.log(req.body.id); // OK
models.visits.update({ _id: req.body.id }, upsertData, { multi: false }, function(err) {
if(err) { throw err; }
console.log('updated visit: '+ req.body.id);
res.redirect('/');
});
}
})
The response is Mod on _id is not allowed.
I just want to update the line such as WHERE id = id in MySQL. I didn't find the right syntax.
According to this question and this other one, the Mod on _id is not allowed occurs when one tries to update an object based on its id without deleting it first.
I also found this github issue which tries to explain a solution. It explicitly states:
Be careful to not use an existing model instance for the update clause
(this won't work and can cause weird behavior like infinite loops).
Also, ensure that the update clause does not have an _id property,
which causes Mongo to return a "Mod on _id not allowed" error.
The solution, it seems, is to do the following:
var upsertData = my_visit.toObject();
console.log(req.body.id); // OK
delete upsertData._id;
models.visits.update({ _id: req.body.id }, upsertData, { multi: false }, function(err) {
if(err) { throw err; }
//...
}
On a side note, you can probably rewrite your route to do both the create and update without the if-else clause. update() takes an extra option upsert, which, according to the docs:
upsert (boolean) whether to create the doc if it doesn't match (false)
Here is my solution:
routes/router.js
router.patch('/user/:id', userController.updateUser)
exports.updateUser = async(req, res) => {
const updates = Object.keys(req.body)
const allowedUpdates = ['name', 'email', 'password', 'age']
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(400).send('Invalid updates!')
}
try {
const user = await UserModel.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true })
if (!user) {
return res.status(404).send()
}
res.status(201).send(user)
} catch (error) {
res.status(400).send(error)
}
}

Resources