I am struggling for a couple of hours to show the final value of an updated document (via mongoose updateOne). I successfully modify it as I can see "nModified: 1" when I call the endpoint on Postman, but I am not able to output the actual final document - even when using the parameter {new:true}
This is the code for the route:
// 3. We check if blockid is in this project
Block.findById(req.params.blockid)
.then(block => {
if (!block) {
errors.noblock = "Block not found";
return res.status(404).json(errors);
}
// 4. We found the block, so we modify it
Block.updateOne(
{ _id: req.params.blockid },
{ $set: blockFields }, // data to be updated
{ new: true }, // flag to show the new updated document
(err, block) => {
if (err) {
errors.noblock = "Block not found";
return res.status(404).json(errors);
}
console.log(block);
res.json(block);
}
);
})
.catch(err => console.error(err));
Instead, this is the output I am getting (Mongoose is on debug mode)
Any ideas?
Many thanks
{ new : true } will return the modified document rather than the original. updateOne doesn't have this option. If you need response as updated document use findOneAndUpdate.
Below are the mongoosejs function where you can use { new : true }
findByIdAndUpdate()
findOneAndUpdate()
findOneAndDelete()
findOneAndRemove()
findOneAndReplace()
Thank you #sivasankar for the answer. Here is the updated working version with findOneAndUpdate
And here the expected result:
you should give second param as object of keys value paris of data,
don't pass as $Set : blockfields, just add like below, if it is object containing parameters,
{ $set: blockFields }
Because code should be like this
Block.updateOne(
{ _id: req.params.blockid },
blockFields, // if blockfields is object containing parameters
{ new: true },
(err, block) => {
// lines of code
}
);
For more detail here is link to updateOne function detail updateOne
Related
I have a NodeJS application with Mongoose ODM(Mongoose 3.3.1). I want to retrieve all fields except 1 from my collection.For Example: I have a collection Product Which have 6 fields,I want to select all except a field "Image" . I used "exclude" method, but got error..
This was my code.
var Query = models.Product.find();
Query.exclude('title Image');
if (req.params.id) {
Query.where('_id', req.params.id);
}
Query.exec(function (err, product) {
if (!err) {
return res.send({ 'statusCode': 200, 'statusText': 'OK', 'data': product });
} else {
return res.send(500);
}
});
But this returns error
Express
500 TypeError: Object #<Query> has no method 'exclude'.........
Also I tried, var Query = models.Product.find().exclude('title','Image'); and var Query = models.Product.find({}).exclude('title','Image'); But getting the same error. How to exclude one/(two) particular fields from a collection in Mongoose.
Use query.select for field selection in the current (3.x) Mongoose builds.
Prefix a field name you want to exclude with a -; so in your case:
Query.select('-Image');
Quick aside: in JavaScript, variables starting with a capital letter should be reserved for constructor functions. So consider renaming Query as query in your code.
I don't know where you read about that .exclude function, because I can't find it in any documentation.
But you can exclude fields by using the second parameter of the find method.
Here is an example from the official documentation:
db.inventory.find( { type: 'food' }, { type:0 } )
This operation returns all documents where the value of the type field is food, but does not include the type field in the output.
Model.findOne({ _id: Your Id}, { password: 0, name: 0 }, function(err, user){
// put your code
});
this code worked in my project. Thanks!! have a nice day.
You could do this
const products = await Product.find().select(['-image'])
I am use this with async await
async (req, res) => {
try {
await User.findById(req.user,'name email',(err, user) => {
if(err || !user){
return res.status(404)
} else {
return res.status(200).json({
user,
});
}
});
} catch (error) {
console.log(error);
}
In the updated version of Mongoose you can use it in this way as below to get selected fields.
user.findById({_id: req.body.id}, 'username phno address').then(response => {
res.status(200).json({
result: true,
details: response
});
}).catch(err => {
res.status(500).json({ result: false });
});
I'm working on a feature. I store a userId array name "collectedUser" than who is collected the project. And I just want to return a field "isCollected" instead of "collectedUsers". So select is not what I want. But I got this solution.
This is after I get projects from database, I add "isCollected".
for (const item of projects) {
item.set("isCollected", item.collectedUsers.includes(userId), {
strict: false,
})
}
And this is in Decorator #Schema
#Schema({
timestamps: true,
toObject: {
virtuals: true,
versionKey: false,
transform: (doc, ret, options): Partial<Project> => {
return {
...ret,
projectManagers: undefined,
projectMembers: undefined,
collectedUsers: undefined
}
}
}
})
Finally in my controller
projects = projects.map(i => i.toObject())
It's a strange tricks that set undefined, but it really work.
Btw I'm using nestjs.
You can do it like this
const products = await Product.find().select({
"image": 0
});
For anyone looking for a way to always omit a field - more like a global option rather than doing so in the query e.g. a password field, using a getter that returns undefined also works
{
password: {
type: String,
required: true,
get: () => undefined,
},
}
NB: Getters must be enabled with option { toObject: { getters:true } }
you can exclude the field from the schema definition
by adding the attribute
excludedField : {
...
select: false,
...
}
whenever you want to add it to your result,
add this to your find()
find().select('+excludedFiled')
I have a schema with sub objects, i want to be able to update a specific key inside of it. If i update only a specific key - like in the Post example - it's empty all the other keys..
for example :
{
"_id": "32323323",
"names":{
"firstname":"John",
"lastname":"foo",
"workers":{
"position":"manager",
"address":"1 st"
}
}
}
I want to update Only "position" key via Post request , for example :
$.post({
url: 'workers/information/',
data: {
user_id: user_id,
names: {
workers: {
position: some data,
}
}
},
success: function (result) {
alert('Your information updated successfully')
}
});
Here is the update method in NodeJs server :
UserDataController.updateWorkersInformation = function (userID, workersInformation, cb) {
if (userID) {
user.findOneAndUpdate({_id: userID}, workersInformation, function (err, result) {
if (err) return cb(err);
return cb(null, result);
});
}
};
You may want to look into mongoose. It provides a more simple interface than the native client does.
https://www.npmjs.com/package/mongoose
However, as the comment mentioned, you are missing the $set operator. {$set:workersInformation}
If update is called without the $set operator, the entire document will be replaced with your update object.
http://mongodb.github.io/node-mongodb-native/2.2/tutorials/crud/
Following code gives me an exception in node js saying: "need to remove or update"
var args = {
query: { _id: _id },
update: { $set: data },
new: true,
remove: false
};
db.collection(COLLECTION.INVENTORY_LOCATION)
.findAndModify(args, function (err, results) {
if (err) {
return callback(err);
} else {
console.log(results);
callback(null, results);
}
});
Not able to figure out the issue as I have specified the update operation.
The syntax is different in the node driver than for the shell, which is the syntax you are using.
db.collection("collection_name").findAndModify(
{ _id: _id }, // query
[], // represents a sort order if multiple matches
{ $set: data }, // update statement
{ new: true }, // options - new to return the modified document
function(err,doc) {
}
);
There is a separate function for .findAndRemove()
As the documentation for the remove parameter of the findAndModify function states:
remove: <boolean>:
Must specify either the remove or the update field. Removes the
document specified in the query field. Set this to true to remove the
selected document . The default is false.
The default value is false so you don't have to provide it at all.
I believe the issue is that you are supplying both update and remove parameters. Try removing the remove parameter.
I'm trying to determine whether the document was found in my findOneAndUpdate operation. If it wasn't, I return a 404 not found error. I figured I'd use the "passRawValue" option Mongoose provides, and check for a raw value- if raw is undefined, I know the doc was not found.
However regardless whether the doc is found or not, my raw value is undefined. I've verified that the doc I'm trying to update is in the DB at the time of the query by running a simple "findOne" query just before the update. Where am I going wrong?
let updateItemById = (userId, itemId, params, cb) => {
//this finds and prints the document I'm testing with -- I know its in the DB
// Item.findOne({ "_id" : itemId, ownerId: userId }, (err, doc) => {
// if (doc) {
// console.log("This is the doc: ", doc);
// }
// });
Item.findOneAndUpdate({ "_id" : itemId, ownerId: userId },
{
$set: {
params
}
}, { runValidators: 1, passRawResult: true}, (err, doc, raw) => {
if (err) {
//winston.log
return cb(ErrorTypes.serverError(), false);
}
else if (raw) {
return cb(null, true);
}
else {
return cb(ErrorTypes.notFound(), false);
}
});
}
Hi I have a hunch that you are passing params that has a property that doesn't exist in the document in the database. In such case, nothing was modified, hence db doesn't return raw as the third parameter.
Update:
So I did some few tests of my own, and I see that if we pass option strict:false then your code should work as intended. So your options section will look like this
{ runValidators: 1, passRawResult: true, strict: false, new:true}
Explanation:
Mongoose has a strict option which by default is true. It makes sure that the values being updated is defined in the schema. So when we provide the option strict as false, as described in the [mongoose documentation] (http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate) we can achieve updating document with new field.
I also added new:true option which will return you the updated document.
P.S.
I would like to add though, since our upsert is false, which means it won't insert new document when a match is not found, it will return null for doc, and you can simple check on that. Why are you checking on raw? Is there any particular reason for this?
I know it's been awhile but I had the same problem here so I decided to leave an answer that maybe can help other people.
I was able to check whether the findOneAndUpdate() method found a document or not by checking if the doc parameter was null on the callback function:
async Update(request: Request, response: Response) {
const productId = request.params.id;
const query = { _id: productId };
const options = { new: true };
try {
await Product.findOneAndUpdate(query, request.body, options, (err, doc, res) => {
if (doc === null)
return response.status(404).send({
error: 'Product not found'
})
return response.status(204).send();
});
}
catch (err) {
return response.status(400).send({
error: 'Product update failed'
});
}
}
In mongoose, we can check if an update operation has modified the document with model.update():
model.update(query, update, function(err, raw){
if (raw.nModified >= 1) console.log('document is modified!')
});
Is there a way to do the same with model.findOneAndUpdate()?
model.findOneAndUpdate(query, update, { new: true }, function(err, doc){
if (doc) {
// So MongoDB found the document, but is there a way
// to know the document was indeed modified?
}
});
You can pass the option { passRawResult : true } to mongoose to advice mongoose to pass the raw result of the underlying mongodb driver, in this case mongodb-native, as a third argument to the callback.
mongodb-native documentation for findOneAndUpdate
model.findOneAndUpdate(query, update, { new: true, passRawResult : true }, function(err, doc, res){
// res will look like
// { value: { _id: 56a9fc80a7f9a4d41c344852, name: 'hugo updated', __v: 0 },
// lastErrorObject: { updatedExisting: true, n: 1 },
// ok: 1 }
});
In case the update did not succeed due to no matching document was found a null res will be passed to the callback. In case a document matched but field values where the same as before the update res object will not give you enough information to figure out if values were updated for the matching document.