Moongoose schema usage for update - node.js

Here is my schema
var DrivingSchema = new Schema({
title: { type: String, required: true },
permalink: {type: String, required: true},
phone: {type: Number, required: true},
mobile: {type: Number},
bike: {type: Boolean, default: false }
});
I used this schema for adding data. It worked fine.
But when I have to update data, I couldn't use this schema because it gave new _id. Here is my controller for update.
DriveModel.findOne({permalink: permalink}, function(err, data) {
if (err)
res.send(err);
var newData = new DriveModel({
title: title,
phone: phone,
mobile: mobile,
bike: bike});
DriveModel.update({_id:data._id}, newData, function(err, result) {
if (err)
res.send(err);
else{res.redirect('/centres/'+permalink);}
});
});
This controller didn't work because of _id conflict. Mongoose Schema documentation suggests to use _id: false in schema but it again works for update not for new insertion of data. Now, how could I solve this issue? Do I have to build another schema just for update or is there anyway to handle with same schema?

Try this one:
var elements = {"title": title, "phone": phone, "mobile": mobile, "bike": bike};
DriveModel.findOne({"permalink": permalink}, function(err, data) {
if (err) {
res.end(err);
}
for(elem in elements) {
data[elem] = elements[elem];
}
data.save(function(err, place) {
if(err) {
res.end(err);
} else {
res.redirect('/centres/'+permalink);
}
});
});

Related

How to update a field-List in MongoDB using Mongoose and Nodehs?

Hello dear Stackoverflow team.
I am trying to patch a user, which can handle several "devices". I am using nodeJs with Express and Mongoose (MongoDB). My User model is the following:
const userSchema = new Schema({
name: {type: String, required: true},
lastname: {type: String, required: true},
email: {type: String, required: true, trim: true, lowercase: true, unique:
true},
password: {type: String, required: true, minlength: 5},
userTyp: {type: String, required: true,
enum: {values: ['Administrator', 'Doctor','Patient','Optiker'], message:
'{VALUE} is not supported' }},
image: {type: String},
devices: [ {device: {type: Schema.Types.ObjectId, ref: "Device"}} ]
});
and I want to have something like this everytime i do a patch:
{
"user": {
"_id": "6138cd30ffc5239bba72e6c0",
"name": "Fernando",
"lastname": "Gonzalez",
"email": "f.gonzalez#unitransferklinik.de",
"password": "Hol087+/*",
"userTyp": "Administrator",
"image": "sdsadsadsa/asdfasdas",
"devices": [
{
"device": "6138c7587ab4b5fc4d369230"
},
{
"device": "6138c7587ab4b5fc4d365210"
}
],
}
}
How can I implement in my function:
const updateUser = async (req, res, next) => {
const { name, lastname, email, password, userTyp, device } = req.body;
const userID = req.params.userID;
let updatedUser;
try {
updatedUser = await User.findById(userID);
}catch(err){
console.log(err);
return next(new HttpError('Something happend.', 500));
}
updatedUser.name = name;
updatedUser.devices = [device, ...updatedUser.devices];
try{
updatedUser.save();
}catch (err) {
return next(new HttpError('It could not uodate device.', 500));
}
});
res.status(200).json({user: updatedUser.toObject( {getters: true} )});
};
In easy words, I want to updated the list everytime that i do a patch with a new device, and I can fetch later all the device list per user.
Thanks a lot!
regards,
Eliot
You can use findOneAndUpdate function of mongoose library
const dynamicModel = libMongoose.model(collection_name, userSchema);
var filter = { userID: req.params.userID };
var update = { name: name, devices : [...device, ...updatedUser.devices]};
//callback approach
dynamicModel.findOneAndUpdate(filter, update, (err, resp) => {
if(err) {
console.log("Error while updating record " + JSON.stringify(err));
}
if(!resp) {
console.log("Couldn't find record");
} else {
console.log("Updated data to DB");
}
});
You can also refer here for async await, Hope this helps!

Update single sub-document attribute with Mongoose

I have a Mongo Collection with an array of sub-documents, like so:
var aliasSchema = new Schema({
name: String,
alias_type: String,
isCommonName: { type: Boolean, default: false }
});
var parentSchema = new Schema(
{
name: String,
description: { type: String, required: false },
observation: { type: String, required: false },
indexed: { type: Boolean, default: true },
aliases: [aliasSchema],
}
I wanted to update a single alias object's alias_type.
I have tried using two approaches with Mongoose
1.
Parent.findOneAndUpdate({'aliases.name': aliasName },{$set: {"aliases.$.alias_type": req.body.aliasForm.alias_type}}, {new: true}, function(err, aliasDoc) {
if (err) {
res.status(400)
res.send(err);
}
console.log(aliasDoc);
res.status(200);
res.send(aliasDoc);
});
and
2.
Parent.update({'aliases.name': aliasName },{$set: {"aliases.$.alias_type": req.body.aliasForm.alias_type}}, function(err, aliasDoc) {
if (err) {
res.status(400)
res.send(err);
}
console.log(aliasDoc);
res.status(200);
res.send(aliasDoc);
});
However, I am still unsuccessful in updating the alias_type.
When I ran option (1) in the mongo console like so, it worked:
db.getCollection('parent').findOneAndUpdate({'aliases.name': 'SomeValue' },{$set:{'aliases.$.alias_type': 'AnotherValue'}})
Can anyone tell me what I am doing wrong?
I was making a mistake while calling one of the parameters. The update() technique that I posted in the question worked :)

Mongoose nested schemas

I'm creating an app where you log workouts and I'm having some problems with Mongoose.
I have two schemas, one for workouts and one for exercises. When the user adds a new exercise, I want it to be stored inside the workout, and I've been trying this in a bunch of ways.
For now, the exercises are saved in a different collection in my MongoDB (don't know if this is the best way to do it), and I thought that it should save the exercise inside the workout.exercises, but there is only the objectID. How do I resolve this? Have looked at the populate function, but can't figure out how to get it to work.
addExercises
export function addExercise(req, res) {
if (!req.body.exercise.title) {
res.status(403).end();
}
const newExercise = new Exercise(req.body.exercise);
// Let's sanitize inputs
newExercise.title = sanitizeHtml(newExercise.title);
newExercise.cuid = cuid();
newExercise.sets = [];
newExercise.save((err, saved) => {
if (err) res.status(500).send(err);
});
Workout
.findOneAndUpdate(
{cuid: req.body.exercise.workoutCUID},
{$push: {exercises: newExercise}},
{upsert: true, new: true},
function (err, data) {
if (err) console.log(err);
});
}
getExercises
export function getExercises(req, res) {
Workout.findOne({cuid: req.params.cuid}).exec((err, workout) => {
if (err) {
res.status(500).send(err);
}
console.log(workout);
let exercises = workout.exercises;
res.json({exercises});
});
}
Workout
import mongoose from "mongoose";
const Schema = mongoose.Schema;
var Exercise = require('./exercise');
const workoutSchema = new Schema({
title: {type: 'String', required: true},
cuid: {type: 'String', required: true},
slug: {type: 'String', required: true},
userID: {type: 'String', required: true},
exercises: [{ type: Schema.Types.ObjectId, ref: 'Exercise' }],
date: {type: 'Date', default: Date.now, required: true},
});
export default mongoose.model('Workout', workoutSchema);
Exercise
import mongoose from "mongoose";
const Schema = mongoose.Schema;
var Workout = require('./workout');
const exerciseSchema = new Schema({
title: {type: 'String', required: true},
cuid: {type: 'String', required: true},
workoutCUID: {type: 'String', required: true},
sets: {type: 'Array', "default": [], required: true}
});
export default mongoose.model('Exercise', exerciseSchema);
Based on your Workout schema, you declare the type of the Exercises field to be [{ type: Schema.Types.ObjectId, ref: 'Exercise' }]. This means that this field should be an array of Mongoose ObjectId's.
It appears that you are attempting to add the whole exercise object to the workout's exercises field, rather than just the ObjectId. Try modifying it this way:
const newExercise = new Exercise(req.body.exercise);
// Let's sanitize inputs
newExercise.title = sanitizeHtml(newExercise.title);
newExercise.cuid = cuid();
newExercise.sets = [];
newExercise.save((err, saved) => {
if (err) res.status(500).send(err);
// Nest the Workout update in here to ensure that the new exercise saved correctly before proceeding
Workout
.findOneAndUpdate(
{cuid: req.body.exercise.workoutCUID},
// push just the _id, not the whole object
{$push: {exercises: newExercise._id}},
{upsert: true, new: true},
function (err, data) {
if (err) console.log(err);
});
});
Now that you correctly have the ObjectId saved in the exercises field, .populate should work when you query the workout:
Workout.findById(id).populate("exercises").exec((err, workout) => {
// handle error and do stuff with the workout
})
Workout.findById(req.params.id).populate("exercises").exec((err,workout) =>{
res.status(200).json(workout);
})
It should work this way

Mongoose Subdocument array pushing

My scenario is if person1 accepting person2 deal means..the person1_id will save inside that person2 particular deal field accepted,i have tried the code it was working perfectly if a accepted user(person2) has one deal but in case of more than one deal it was updating but deleting other deals (i.e,the suppose the person2 having 3 deals means if person1 accepting 3rd deal the accepted user id was updating in 3rd deal and the 1st and 2nd deal was deleted).Anyone please help me how to save only the updated deal array
var incomingUser = req.user;//accepting user accesstoken in header(person1)
if(req.params.id){
var id = req.params.id;//deal id
console.log("DealId:"+id + "Acceptinguser:"+incomingUser.name);
User.findOne(
{
"deals": {
$elemMatch: {
_id: id
}
}
},
function(err, data){
console.log("Dealer:" +data.name);
console.log("deal:"+ data.deals);
if(err){
console.log("User not found");
res.send(new restify.ResourceNotFoundError('failed','Deal not found'));
return next();
}
var dealObj = _.filter(data.deals, { id: id })[0];
console.log("Deal Obj" + dealObj);
var acceptingUser = incomingUser;
console.log("accepting user:" +acceptingUser._id);
dealObj.accepted = acceptingUser._id;
console.log("accept id: "+ dealObj.accepted);
data.deals = dealObj;
console.log("data:"+ data.deals);
data.save(function (err, result){
console.log("Result:" + result);
if(err){
console.log("Internal error");
res.send(new restifyc.InternalError('failed','Error accepting'));
return next();
}
console.log("saved");
res.send(200,{user: result});
return next();
});
});
}
}
And my schema is
var dealSchema = new mongoose.Schema({
shopName: {type: String,required: true},
deal: {type: String,required: true},
price:{type: Number,required: true},
start:{type: Date,default: Date.now},
end:{type: Date},
expiry:{type: Date},
comments:{type: String},
accepted: {type:mongoose.Schema.Types.ObjectId, ref:'user'},//person1 _id
rejected: {type:mongoose.Schema.Types.ObjectId, ref: 'user'}
});
var userSchema = new mongoose.Schema({
name: { type: String,required: true},
phone: { type: Number, required: true,unique: true},
email:{type: String},
password: {type: String},
deals:[dealSchema]
}, {collection: 'user'});
mongoose.model('Deal', dealSchema);
mongoose.model('user', userSchema);
Yep in order to update specifically what you need you can use the <array>.$ for the specified position of the element:
User.update(
"deals": {
$elemMatch: {
_id: id
}
}, {
"$set": {
"deals.$" : {/*your deal data*/}
}
}, function(err, doc) {
});
More details on how to use the $ wildcard https://docs.mongodb.org/manual/reference/operator/update/positional/

Cannot pull from mongoose array

In my schema I have two arrays with users, invitedUsers and joinedUsers. Invited array is created from request body
invitedUsers: req.body.invitedUsers
Joined array is updated when user clicks 'Join'
$addToSet: {joinedUsers: req.user}
I can then pull user from joinedUsers array by performing
{$pull: {joinedUsers: {_id: req.user._id}}}
However, I can't pull from invited users array, although user object is the same. Here is the complete code:
app.put('/decline/events/:id', function (req, res) {
var update = {$pull: {invitedUsers: {_id: req.user._id}}};
console.log(req.user._id);
Event.findByIdAndUpdate(req.params.id, update, function (err, event) {
if (err) {
res.send(err);
};
Event.find({})
.populate('owner')
.exec(function (err, events) {
if (err) {
res.send(err);
};
res.json(events)
});
});
});
Ajax call on client
$scope.declineInvitation = function (id) {
$http.put('/decline/events/' + id)
.success(function (data) {
})
.error(function (data) {
console.log('Error: ' + data);
});
};
Everything goes without errors, but invitedArray doesn't change, as if mongoose fails to find it. What might be a solution to this?
Update
Event Schema definition, as requested:
var eventSchema = new Schema({
title: {type: String},
description: {type: String, default: ''},
startDate: Date,
invitedUsers: {type: Array, default: []},
joinedUsers: {type: Array, default: []},
owner: {type: Schema.Types.ObjectId, ref: 'User'},
created_at: {type: Date, default: Date.now()},
updated_at: {type: Date, default: null},
location: String
}
The problem was because the _id in invitedUsers is a String and req.user._id is an ObjectId.
Calling toString() on _id will solve it:
var update = {$pull: {invitedUsers: {_id: req.user._id.toString()}}};

Resources