Issue in saving values in array in mongoose model using save() [duplicate] - node.js

This question already has answers here:
Push items into mongo array via mongoose
(11 answers)
Closed 5 years ago.
I am trying to update a document in a collection. I am particularly trying to update an array of Strings.The following is my Schema
var sampleSchema= mongoose.Schema({
fullName : String,
email : String,
rolesTaken : [String],
});
I basically have an array of such schema's. I want to update the rolesTaken array for all of them.
So I did the following
var async = require('async');
var ATmapping = require('path to Schema');
ATmapping.find({},function(err,lists){
if(err){
console.log(err);
return;
}
if(lists.length > 0){
async.each(lists,function(list,callback){
if(!list.rolesTaken){
list.rolesTaken =[];
}
list.rolesTaken.push("Patient");
list.markModified('rolesTaken');
list.save(function(err,item){
if (err){
console.log(err);
}
console.log('Saved', item);
callback();
});
});
}
});
I have browsed a lot and the most popular solution was to add markModified. But it doesn't seem to work in my case.When I added mongoose.debug i got the following
atmappings.update({ _id: ObjectId("59074b127adeef0004b84ac3"), __v: 7 }, { '$set': { rolesTaken: [] }, '$inc': { __v: 1 } })
As you can see the roles taken is empty despite me adding markmodified and save(). I would like to know if I am missing something which is preventing me from saving the values in the schema.
Thanks in advance.

Here is how I push a comment to a thread in one of my apps using mongoose.
Thread.findByIdAndUpdate(body.thread, { $push: { comments: comment.id }})
I simply find the thread by the id, then use the $push operator to push the comment id to the comments attribute where I populate later.
You can read more into the $push operator here (mongoose v3.4) https://docs.mongodb.com/manual/reference/operator/update/push/

Related

findByIdAndUpdate does not work in express, but does work in mongo tool [duplicate]

This question already has answers here:
Mongoose: findOneAndUpdate doesn't return updated document
(16 answers)
How to push an array of objects into an array in mongoose with one call?
(4 answers)
Push to two separate arrays in one update call in mongodb
(1 answer)
Closed 4 years ago.
I am a beginner of mongodb and express, now I am trying to update some data. I do not think there is something wrong in my code, when I turn debugging on, the following db operation is printed out and does not return any error from catch, therefore without any doubt, I thought the following update is executed without fail. Even I tested with the following update statement directly from mongo client tool, it worked fine. However it is not reflected on the actual database if I update from express. If updating is not successful, it should return some error, but it does not. Could you anyone give me some advice for this? I really do not know what is happening here, the following db operation works well from the mongo client tool. From express, it does not return error also. So, I come to ask about this.
Mongoose: persons.findOneAndUpdate({ _id: ObjectId("5be6d1087594078eac687f19") }, { '$push': { hobbies: { '$each': [ 'TEST', 'SING', 'SWIM' ] } } }, { '$push': { skills: [ 'programming' ] }, upsert: false, projection: {}, returnOriginal: true })
router.post("/edit/:id", (req, res, next) => {
var hobbies = req.body.hobbies.split(",");
var skills = req.body.skills.split(",");
Person.findByIdAndUpdate(
req.params.id,
// { $set: { name: req.body.name } }
{ $push: { hobbies: hobbies} },
{ $push: { skills: skills} }
)
.exec()
.then(person=> {
res.json(person);
})
.catch(err => {
console.log("ERROR", err);
});
});

push array in array field in mongodb [duplicate]

This question already has answers here:
Push items into mongo array via mongoose
(11 answers)
Closed 4 years ago.
I have an array called students in a schema called Course. I created a route that allows me to add students to this array using a student's ObjectID like so:
router.put('/addStudent/:courseID', function (req, res) {
Course.findOneAndUpdate({courseID: req.params.courseID}, {$push: {students: req.body.students}})
.populate('students')
.exec(function (err, course) {
if (err) return res.status(500).send("There was a problem adding this information to the database");
res.status(201).send(course);
})
});
When I try making a PUT request to my endpoint with the following JSON body:
{
"students":["5b1f06cafa355c2d187c344f"]
}
Nothing happens at all, it just sends me back the course with the student ID not added. How do I make it so I could add more student IDs to the array? I don't want it to replace the array with a student ID, I want to keep adding more as I make more requests.
Thanks!
You need to use $each with $push
Course.findOneAndUpdate(
{ courseID: req.params.courseID },
{ $push: { students: { $each: req.body.students } } }
)
Course.findOneAndUpdate(
{ courseID: req.params.courseID },
{ $addToSet: { students: { $each: req.body.students } } }
)
put request will update your db and findOneAndUpdate method from mongoose is also for updating you current item, you need to use post request and save method in mongoose instead if you want create a new item.
You can Try this:
Course.findOneAndUpdate(
{ courseID: req.params.courseID },
{ $push: {
students: req.body.students
}}, options, function(err, values){
});

Mongoose: How to push in nested array? [duplicate]

This question already has answers here:
Updating a Nested Array with MongoDB
(2 answers)
Closed 3 years ago.
I am very new to NoSQL world. Here the screenshot of my Mongoose schema.
I need to insert,update and delete document to/from vehicles array.
What I have tried so far:
Add: (Working)
Companies.findOne({'mobile' : givenMobileNumber, 'VehicleGroups.vehicle_group_id' : vehicleGroupId}, (err, res) => {
if( err || res == null) {
callback(err, res);
}else{
var len = res.VehicleGroups.length;
for(var i=0; i<len; i++)
{
if(res.VehicleGroups[i].vehicle_group_id == vehicleGroupId)
res.VehicleGroups[i].vehicles.push(data);
}
res.save(callback);
}
})
Delete: (Working)
Companies.findOneAndUpdate({ mobile : givenMobileNumber, 'VehicleGroups.vehicle_group_id' : vehicleGroupId},
{ $pull : {'VehicleGroups.$.vehicles' : { 'vehicle_id' : vehicleId} } }, callback);
Still working to update data. Is my approach valid?
Thanks
You can consider setting up separate schemas for your VehicleGroups and vehicles and reference them through ObjectId in your Companies schema:
VehicleGroups: [{
_id: { type: Schema.Types.ObjectId, ref: 'vehicleGroup' },
// All other properties here
vehicles: [{ type: Schema.Types.ObjectId, ref: 'vehicle' }]
}]
Adding a new document to theVehicleGroup schema would then go something like this:
const newVehicleGroup = new VehicleGroup({
name: 'New Vehicle',
// Set all other fields
})
And adding it to the Companies schema:
Companies.findOneAndUpdate({
mobile : givenMobileNumber, 'VehicleGroups.vehicle_group_id' : vehicleGroupId,
{ $push: { vehicleGroups: newVehicleGroup._id } }
})
Since you reference vehicles and VehicleGroups by ObjectId, all you have to do to update that reference is to update the document in the respective collection.
However, if you delete a document you will need to remove its reference from the respective array in the Companies collection.
See if this approach makes it a little easier!

How to get a specific object from an array field with mongoose [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 8 years ago.
Given a schema like this:
UserSchema = new Schema({
name: String,
donations: [
{
amount: Number,
charity: {
type: Schema.Types.ObjectId,
ref: 'charity'
}
}
]
});
I have the (string) ids of a user and of a nonprofit and I want to get the amount the user donated. Im using this query with lodash:
User.findOne({
_id: userId
}, function(err, user) {
var amount = _.find(user.donations, {charity: charityId});
console.log("the amount is: ", amount);
});
Here the amount returns undefined even though it shouldn't also im guessing i shouldn't have to use lodash. What's the right way to get to the amount donated given a specific userId and charityId?
This is pretty similar to the possible duplicate I linked to, as you can do this without using lodash as:
User.findOne({
_id: userId,
'donations.charity': charityId
}, {
'donations.$': 1
}, function(err, user) {
console.log("the amount is: ", user.donations[0].amount);
});

Incorrect Subdocument Being Updated?

I've got a Schema with an array of subdocuments, I need to update just one of them. I do a findOne with the ID of the subdocument then cut down the response to just that subdocument at position 0 in the returned array.
No matter what I do, I can only get the first subdocument in the parent document to update, even when it should be the 2nd, 3rd, etc. Only the first gets updated no matter what. As far as I can tell it should be working, but I'm not a MongoDB or Mongoose expert, so I'm obviously wrong somewhere.
var template = req.params.template;
var page = req.params.page;
console.log('Template ID: ' + template);
db.Template.findOne({'pages._id': page}, {'pages.$': 1}, function (err, tmpl) {
console.log('Matched Template ID: ' + tmpl._id);
var pagePath = tmpl.pages[0].body;
if(req.body.file) {
tmpl.pages[0].background = req.body.filename;
tmpl.save(function (err, updTmpl) {
console.log(updTmpl);
if (err) console.log(err);
});
// db.Template.findOne(tmpl._id, function (err, tpl) {
// console.log('Additional Matched ID: ' + tmpl._id);
// console.log(tpl);
// tpl.pages[tmpl.pages[0].number].background = req.body.filename;
// tpl.save(function (err, updTmpl){
// if (err) console.log(err);
// });
// });
}
In the console, all of the ID's match up properly, and even when I return the updTmpl, it's saying that it's updated the proper record, even though its actually updated the first subdocument and not the one it's saying it has.
The schema just in case:
var envelopeSchema = new Schema({
background: String,
body: String
});
var pageSchema = new Schema({
background: String,
number: Number,
body: String
});
var templateSchema = new Schema({
name: { type: String, required: true, unique: true },
envelope: [envelopeSchema],
pagecount: Number,
pages: [pageSchema]
});
templateSchema.plugin(timestamps);
module.exports = mongoose.model("Template", templateSchema);
First, if you need req.body.file to be set in order for the update to execute I would recommend checking that before you run the query.
Also, is that a typo and req.body.file is supposed to be req.body.filename? I will assume it is for the example.
Additionally, and I have not done serious testing on this, but I believe your call will be more efficient if you specify your Template._id:
var template_id = req.params.template,
page_id = req.params.page;
if(req.body.filename){
db.Template.update({_id: template_id, 'pages._id': page_id},
{ $set: {'pages.$.background': req.body.filename} },
function(err, res){
if(err){
// err
} else {
// success
}
});
} else {
// return error / missing data
}
Mongoose doesn't understand documents returned with the positional projection operator. It always updates an array of subdocuments positionally, not by id. You may be interested in looking at the actual queries that mongoose is building - use mongoose.set('debug', true).
You'll have to either get the entire array, or build your own MongoDB query and go around mongoose. I would suggest the former; if pulling the entire array is going to cause performance issues, you're probably better off making each of the subdocuments a top-level document - documents that grow without bounds become problematic (at the very least because Mongo has a hard document size limit).
I'm not familiar with mongoose but the Mongo update query might be:
db.Template.update( { "pages._id": page }, { $set: { "pages.$.body" : body } } )

Resources