How can I update multiple documents in mongoose? - mongodb

I found the following script:
Device.find(function(err, devices) {
devices.forEach(function(device) {
device.cid = '';
device.save();
});
});
MongoDB has the "multi" flag for an update over multiple documents but I wasn't able to get this working with mongoose. Is this not yet supported or am I doing something wrong?
Device.update({}, {cid: ''}, false, true, function (err) {
//...
});

Currently I believe that update() in Mongoose has some problems, see:
https://groups.google.com/forum/#%21topic/mongoose-orm/G8i9S7E8Erg
and https://groups.google.com/d/topic/mongoose-orm/K5pSHT4hJ_A/discussion.
However, check the docs for update: http://mongoosejs.com/docs/api.html (its under Model). The definition is:
Earlier Solution(Depreciated after mongoose 5+ version)
Model.update = function (query, doc, options, callback) { ... }
You need to pass the options inside an object, so your code would be:
Model.update = function ({}, {cid: ''}, {multi: true}, function(err) { ... });
New Solution
Model.updateMany = function (query, doc, callback) { ... }
Model.updateMany = function ({}, {cid: ''}, function(err) { ... });
I believe that Mongoose wraps your cid in a $set, so this is not the same as running that same update in the mongo shell. If you ran that in the shell then all documents would be replaced by one with a single cid: ''.

Those answers are deprecated. This is the actual solution:
Device.updateMany({}, { cid: '' });

You have to use the multi: true option
Device.update({},{cid: ''},{multi: true});

as mentioned in the mongoose documents this is how we do this:
db.collection.updateMany(condition, update, options, callback function)
so this is an example based on the docs:
// creating arguments
let conditions = {};
let update = {
$set : {
title : req.body.title,
description : req.body.description,
markdown : req.body.markdown
}
};
let options = { multi: true, upsert: true };
// update_many :)
YourCollection.updateMany(
conditions, update, options,(err, doc) => {
console.log(req.body);
if(!err) {
res.redirect('/articles');
}
else {
if(err.name == "ValidationError"){
handleValidationError(err , req.body);
res.redirect('/new-post');
}else {
res.redirect('/');
}
}
});
this worked fine for me, I hope it helps :)

await Device.updateMany({_id: {$in: cid}},{ $set: {columnNameHere: "columnValueHere"}},{multi:true,upsert: true,new: true});

as #sina mentioned:
let conditions = {};
let options = { multi: true, upsert: true };
Device.updateMany(conditions , { cid: '' },options );
you can add a callback function after options but it's not necessary.

You can try the following way
try {
const icMessages = await IcMessages.updateMany({
room: req.params.room
}, {
"$set": {
seen_status_2: "0"
}
}, {
"multi": true
});
res.json(icMessages)
} catch (err) {
console.log(err.message)
res.status(500).json({
message: err.message
})
}

Related

I use mongoDB's findOneAndUpdate with { returnOriginal: false } but it doesn't work

When I use MongoDB's findOneAndUpdate and I have declaration { returnOriginal: false } but it doesn't work and when I update successfully it returns me stale data I expect to return the data after update.
My MongoDB version is "4.1.0".
const update = async (id, data) => {
try {
const result = await getDB()
.collection(columnCollectionName)
.findOneAndUpdate(
{ _id: ObjectId(id) },
{ $set: data },
{ returnOriginal: false }
);
return result.value;
} catch (error) {
throw new Error(error);
}
};
The documentation says we need to use {new : true}, but it didn't really work for me.
What worked for me is - {returnDocument:"after"} (another option instead of "after" is "before")
Instead of { returnOriginal: false } use { new: true }

Mongoose: findByIdAndUpdate() How To Conditionally Update Based On Existing Data?

When using findByIdAndUpdate() or findOneAndUpdate() (that is, updating the database atomically to avoid race conditions), is there a way to reference the existing data to conditionally update a field?
PersonModel.findByIdAndUpdate(
req.user.id,
{
$set: {
// set this to true
// if person.color === blue for example
hasFavoriteColor: true,
}
},
{ new: true },
(err, updatedDoc => {
if (err) return;
return updatedDoc;
});
);
I'm not sure you can do that, I see nowhere in the document. However, for your query particularly, you can add the condition about the color in the filter part, something like this :
PersonModel.findOneAndUpdate(
{_id : req.user.id, color : "blue"},
{
$set: {
// set this to true
// if person.color === blue for example
hasFavoriteColor: true,
}
},
{ new: true },
(err, updatedDoc => {
if (err) return;
return updatedDoc;
});
);

Can't add array to mongodb

I'm trying to send an array to mongodb, but the res.json(user) returns an empty biddingGroup:[] and mongodb document never has field biddingGroup appear. I've looked at stack posts and have seen suggestions for schema.
I've tried
biddingGroup: [{type: String}],
biddingGroup: [String],
biddingGroup: {type: String},
I haven't found a working schema that captures the data yet.
I even hardcoded biddingGroup: ['test'] too, but it never shows up.
app.js
app.put('/api/listings/:id', (req, res) =>
Post.update({
id: req.query.id
}, {
$set: {
currentBid: req.query.currentBid,
lastBidTimeStamp: req.params.lastBidTimeStamp,
biddingGroup: ['test']
}
}, {
multi: false //set to false to ensure only one document gets updated
}).exec().then(data => {
console.log(data);
}, err => {
console.log(err);
})
);
Any help is appreciated.
You need to use exec() at the end to run the query. That is the function that actually runs the request and returns you the promise. Plus your usage of the update function in general is off.
Try this:
Post.update({
id: req.query.id
}, {
$set: {
currentBid: req.query.currentBid,
lastBidTimeStamp: req.params.lastBidTimeStamp,
biddingGroup: ['test']
}
}, {
multi: false //set to false to ensure only one document gets updated
}).exec().then(data => {
console.log(data);
}, err => {
console.log(err);
});

Update query adding ObjectIDs to array twice

I am working on a table planner application where guests can be assigned to tables. The table model has the following Schema:
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const tableSchema = new mongoose.Schema({
name: {
type: String,
required: 'Please provide the name of the table',
trim: true,
},
capacity: {
type: Number,
required: 'Please provide the capacity of the table',
},
guests: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Guest',
}],
});
module.exports = mongoose.model('Table', tableSchema);
Guests can be dragged and dropped in the App (using React DND) to "Table" React components. Upon being dropped on a table, an Axios POST request is made to a Node.js method to update the Database and add the guest's Object ID to an array within the Table model:
exports.updateTableGuests = async (req, res) => {
console.log(req.body.guestId);
await Table.findOneAndUpdate(
{ name: req.body.tablename },
{ $push: { guests: req.body.guestId } },
{ safe: true, upsert: true },
(err) => {
if (err) {
console.log(err);
} else {
// do stuff
}
},
);
res.send('back');
};
This is working as expected, except that with each dropped guest, the Table model's guests array is updated with the same guest Object ID twice? Does anyone know why this would be?
I have tried logging the req.body.guestID to ensure that it is a single value and also to check that this function is not being called twice. But neither of those tests brought unexpected results. I therefore suspect something is wrong with my findOneAndUpdate query?
Don't use $push operator here, you need to use $addToSet operator instead...
The $push operator can update the array with same value many times
where as The $addToSet operator adds a value to an array unless the
value is already present.
exports.updateTableGuests = async (req, res) => {
console.log(req.body.guestId);
await Table.findOneAndUpdate(
{ name: req.body.tablename },
{ $addToSet : { guests: req.body.guestId } },
{ safe: true, upsert: true },
(err) => {
if (err) {
console.log(err);
} else {
// do stuff
}
},
);
res.send('back');
};
I am not sure if addToSet is the best solution because the query being executed twice.
If you used a callback and a promise simultaneously, it would make the query executes twice.
So choosing one of them would make it works fine.
Like below:
async updateField({ fieldName, shop_id, item }) {
return Shop.findByIdAndUpdate(
shop_id,
{ $push: { menuItems: item } },
{ upsert: true, new: true }
);
}

How to update embedded document in mongoose?

I've looked through the mongoose API, and many questions on SO and on the google group, and still can't figure out updating embedded documents.
I'm trying to update this particular userListings object with the contents of args.
for (var i = 0; i < req.user.userListings.length; i++) {
if (req.user.userListings[i].listingId == req.params.listingId) {
User.update({
_id: req.user._id,
'userListings._id': req.user.userListings[i]._id
}, {
'userListings.isRead': args.isRead,
'userListings.isFavorite': args.isFavorite,
'userListings.isArchived': args.isArchived
}, function(err, user) {
res.send(user);
});
}
}
Here are the schemas:
var userListingSchema = new mongoose.Schema({
listingId: ObjectId,
isRead: {
type: Boolean,
default: true
},
isFavorite: {
type: Boolean,
default: false
},
isArchived: {
type: Boolean,
default: false
}
});
var userSchema = new mongoose.Schema({
userListings: [userListingSchema]
});
This find also doesn't work, which is probably the first issue:
User.find({
'_id': req.user._id,
'userListings._id': req.user.userListings[i]._id
}, function(err, user) {
console.log(err ? err : user);
});
which returns:
{ stack: [Getter/Setter],
arguments: [ 'path', undefined ],
type: 'non_object_property_call',
message: [Getter/Setter] }
That should be the equivalent of this mongo client call:
db.users.find({'userListings._id': ObjectId("4e44850101fde3a3f3000002"), _id: ObjectId("4e4483912bb87f8ef2000212")})
Running:
mongoose v1.8.1
mongoose-auth v0.0.11
node v0.4.10
when you already have the user, you can just do something like this:
var listing = req.user.userListings.id(req.params.listingId);
listing.isRead = args.isRead;
listing.isFavorite = args.isFavorite;
listing.isArchived = args.isArchived;
req.user.save(function (err) {
// ...
});
as found here: http://mongoosejs.com/docs/subdocs.html
Finding a sub-document
Each document has an _id. DocumentArrays have a special id method for looking up a document by its _id.
var doc = parent.children.id(id);
* * warning * *
as #zach pointed out, you have to declare the sub-document's schema before the actual document 's schema to be able to use the id() method.
Is this just a mismatch on variables names?
You have user.userListings[i].listingId in the for loop but user.userListings[i]._id in the find.
Are you looking for listingId or _id?
You have to save the parent object, and markModified the nested document.
That´s the way we do it
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Profile.findById(req.params.id, function (err, profile) {
if (err) { return handleError(res, err); }
if(!profile) { return res.send(404); }
var updated = _.merge(profile, req.body);
updated.markModified('NestedObj');
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(200, profile);
});
});
};