Auto increase in mongoose - node.js

I have a Model : OrderEventSchema
var OrderEventSchema = new Schema(
{
orderId: { type: String, required: true },
sequence: { type: Number },
workflowId: { type: String, required: true },
type: { type: String },
transitionId: { type: String },
placeId: { type: String },
eventType: { type: String },
payLoad: { type: Schema.Types.Mixed }
}, options
);
Handle Post save :
OrderEventSchema.post('save', function(doc) {
getNextSequence(doc.orderId)
.then(function(nextSequence) {
doc.sequence = nextSequence;
doc.save();
})
})
function getNextSequence (orderId) {
return new Promise(function(resolve, reject) {
orderEvent.findOne({
orderId : orderId
}).sort({'sequence' : -1}).limit(1).exec(function(err, doc) {
if (err) {
reject(err);
} else {
resolve(doc.sequence ? doc.sequence + 1 : 1);
}
});
})
}
Now, everything I save, it will get a infinite loop, can anyone help me, how can I increase the sequence without using another module, how can I improve this code.
Thank you so much.

Related

Problem with update a single doc in monogdb using express and mongoose

I'm quiet new to mongodb and I'm actually trying to implement a follow-unfollow method in the backend
there are two types of users in the database
Mentors and mentees
only mentees can follow the mentors and mentors can only accept the request
the schema
Mentors
const MentorsSchema = mongoose.Schema({
name: { type: String, required: true },
designation: { type: String, required: true },
yearNdClass: {
type: String,
required: ["true", "year and class must be spciefied"],
},
respondIn: { type: String, required: true },
tags: {
type: [String],
validate: (v) => v == null || v.length > 0,
},
socialLinks: {
github: { type: String, default: "" },
twitter: { type: String, default: "" },
facebook: { type: String, default: "" },
instagram: { type: String, default: "" },
},
watNum: { type: Number, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
about: { type: String },
followers: [
{ type: mongoose.Schema.Types.ObjectId, ref: "Mentees", default: "" },
],
pending: [
{ type: mongoose.Schema.Types.ObjectId, ref: "Mentees", default: "" },
],
});
Mentee
const MenteeSchema = mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
yearNdClass: {
type: String,
required: ["true", "year and class must be spciefied"],
},
socialLinks: {
github: { type: String },
twitter: { type: String },
facebook: { type: String },
instagram: { type: String },
},
about: { type: String },
skillLooksFor: { type: String, required: true },
watNum: { type: Number, required: true },
following: [{ type: mongoose.Schema.Types.ObjectId, ref: "Mentors",default:"" },
],
});
you can see that there are two fields for mentors both following and pending arrays which consist of the ids of the mentees who follow the mentors and the ids of the mentees which yet to be accepted as a follower
I planned to create an endpoint where when a mentee gives a follow request it should be reached into the mentor pending array so that he can accept it later
so my logic like this
// #desc follow a mentor
// #route POST /api/mentees/follow-mentor/:id
// #access private
menteeRoute.post(
"/follow-mentor/:id",
isAuthorisedMentee,
expressAsyncHandler(async (req, res) => {
const { id } = req.params;
const mentee = await Mentees.findById(req.mentee.id);
const mentor = await Mentors.findById(id).select("-password");
// console.log(mentor)
if (mentee) {
try {
await Mentees.findOneAndUpdate(
{ _id: mongoose.Types.ObjectId(id) },
{ $addToSet: { "following.0": mentor._id } },
{ new: true }
);
await Mentors.findOneAndUpdate(
{ _id: mongoose.Types.ObjectId(mentor._id) },
{
$addToSet: {
"pending.0": id,
},
},
{ new: true },
);
res.json({
data: {
mentor,
mentee,
},
});
} catch (error) {
console.log(error);
throw new Error(error);
}
}
})
);
but the code didn't work.
can anyone help me to resolve the problem?
basically, when a mentee gives a follow request it should update the following array of mentee with the id of mentor and it should also update the pending array of mentor with the id of the mentee
PS: any alternative ideas are also welcome
Try to remove the .0 index and use the $push method.
Also, you should return the updated objects:
menteeRoute.post(
'/follow-mentor/:id',
isAuthorisedMentee,
expressAsyncHandler(async (req, res) => {
const { id } = req.params;
const mentee = await Mentees.findById(req.mentee.id);
const mentor = await Mentors.findById(id).select('-password');
// console.log(mentor)
if (mentee) {
try {
const updatedMentee = await Mentees.findOneAndUpdate(
{ _id: mongoose.Types.ObjectId(id) },
{ $push: { following: mentor._id } },
{ new: true }
);
const updatedMentor = await Mentors.findOneAndUpdate(
{ _id: mentor._id },
{
$push: {
pending: id,
},
},
{ new: true }
);
res.json({
data: {
mentor: updatedMentor,
mentee: updatedMentee,
},
});
} catch (error) {
console.log(error);
throw new Error(error);
}
}
})
);

Cast to ObjectId failed for value at path for model error

This is my Profile Schema:
const mongoose = require('mongoose');
const ProfileSchema = new mongoose.Schema({
user: {
// Special field type because
// it will be associated to different user
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
company: {
type: String,
},
website: {
type: String,
},
location: {
type: String,
},
status: {
type: String,
required: true,
},
skills: {
type: [String],
required: true,
},
bio: {
type: String,
},
githubusername: {
type: String,
},
experience: [
{
title: {
type: String,
required: true,
},
company: {
type: String,
required: true,
},
location: {
type: String,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
education: [
{
school: {
type: String,
required: true,
},
degree: {
type: String,
required: true,
},
fieldofstudy: {
type: String,
required: true,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
social: {
youtube: {
type: String,
},
twitter: {
type: String,
},
facebook: {
type: String,
},
linkedin: {
type: String,
},
instagram: {
type: String,
},
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = Profile = mongoose.model('profile', ProfileSchema);
This is my view api. It doesn't work. it only return Cast to ObjectId failed for value { 'experience._id': '5edcb6933c0bb75b3c90a263' } at path _id for model profile
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findById({
'experience._id': req.params.viewexp_id,
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
How can I fix this? I tried looking at the stackoverflow of the same errors. still it doesn't seem to work.
and this is what I am trying to hit
The problem is that you have to convert your string _id to mongoose object id using this function mongoose.Types.ObjectId and my suggestion is to use findOne function instead of findById,
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
let id = mongoose.Types.ObjectId(req.params.viewexp_id);
const exp = await Profile.findOne(
{ "experience._id": req.params.viewexp_id },
// This will show your sub record only and exclude parent _id
{ "experience.$": 1, "_id": 0 }
);
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findOne({
'experience._id': mongoose.Types.ObjectId(req.params.viewexp_id),
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
You are saving object id . but your param id is string. convert it in ObjectId. Please check my solution.
router.post(
"/",
[
auth,
[
check("status", "status is required").not().isEmpty(),
check("skills", "skills is required").not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubuername,
skills,
youtube,
facebook,
twitter,
instagram,
linkedin,
} = req.body;
const profileFileds = {};
profileFileds.user = req.user.id;
if (company) profileFileds.company = company;
if (website) profileFileds.website = website;
if (location) profileFileds.location = location;
if (bio) profileFileds.bio = bio;
if (status) profileFileds.status = status;
if (githubuername) profileFileds.githubuername = githubuername;
if (skills) {
profileFileds.skills = skills.split(",").map((skill) => skill.trim());
}
//Build profile object
profileFileds.social = {};
if (youtube) profileFileds.social.youtube = youtube;
if (twitter) profileFileds.social.twitter = twitter;
if (facebook) profileFileds.social.facebook = facebook;
if (linkedin) profileFileds.social.linkedin = linkedin;
if (instagram) profileFileds.social.instagram = instagram;
try {
let profile = await Profile.findOne({ user: req.user.id });
if (profile) {
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFileds },
{ new: true }
);
return res.json(profile);
}
//Create profile
profile = new Profile(profileFileds);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send("server Error");
}
}
);

mongoose findByIdAndUpdate instead of save

I'm trying to update the value of an element inside an array of my document.
The common way of update via save works as expected, but trying to use an static method, like findByIdAndUpdate doesn't work as expected.
Here bellow I paste the code I'm currently using:
var UserSchema = new mongoose.Schema({
nickname: { type: String, trim: true},
username: { type: String, trim: true },
notifications: [{
a: {
_id: { type: mongoose.Schema.Types.ObjectId, ref: 'x' },
x: { type: mongoose.Schema.Types.ObjectId, ref: 'y' }
},
b: {
_id: { type: mongoose.Schema.Types.ObjectId, ref: 'y' },
x: { type: mongoose.Schema.Types.ObjectId, ref: 'y' }
},
read: { type: Number, default: 0 }, // 0 - Unread, 1 - read
ts: { type: Date, default: Date.now }
}]
}, { timestamps: { createdAt: 'created_at' } });
// This works as expected
UserSchema.statics.rNSave = function (user_id, notification_id) {
var vm = this;
return new Promise(function (resolve, reject) {
vm.findById(user_id, function (err, data) {
if (err) {
reject(new Error(err));
} else {
var notifications = data.notifications, i = 0;
for (i; i < notifications.length; i += 1) {
if (data.notifications[i]._id.toString() === notification_id) {
data.notifications[i].read = 1;
data.save({ validateBeforeSave: false }, function (err, updatedData) {
if (err) {
reject(new Error(err));
} else {
resolve();
}
});
return;
}
}
return reject('Error');
}
});
});
};
// This one is not working
UserSchema.statics.rNStatic = function (user_id, notification_id) {
return this.findByIdAndUpdate({ _id: user_id, notifications: { $elemMatch: { _id: notification_id }}}, { $set: { 'notifications.$.read': 1 }}).exec();
};
Any help with this?
Thanks in advice.

Mongoose Schema.update doesn't update boolean

I have tried updating other fields and it works just fine.
The command I am using in my API:
User.update({ email: targetUser.email }, { $set: { isAdmin: true }, $push: { 'log.updated': new Date() } }, function (err, user) {
if (err) {
responseObject.err = err;
responseObject.data = null;
responseObject.code = 422;
return res.json(responseObject);
}
return res.json(responseObject);
});
To clarify, when I try to run this, the API returns a code 200, meaning everything worked fine, but when I check the database the isAdmin value wasn't changed.
Any suggestions would be helpful, running out of ideas here!
User Schema as requested:
var UserSchema = new Schema({
name: { type: String, default: "", index: 'text' },
email: { type: String, lowercase: true },
role: { type: String, default: "" },
meta: {
skills: { type: Array, default: [], index: 'text' },
about: { type: String, default: "", index: 'text' },
education: { type: Array, default: [], index: 'text' },
location: {
address: {
a: { type: String, default: "" },
p: { type: String, default: "" },
c: { type: String, default: "" }
},
geo: {
lat: { type: Number, default: 0 },
lng: { type: Number, default: 0 }
}
}
},
compMeta:
{
departments: { type: Array, default: [], index: 'text' },
employees:
[
{
emId: Number,
empName: String,
empDep: String // Dunno if i should use Dep name or Dep ID gonna look in to that later
}
],
}
,
settings: {
search: {
distance: {
n: { type: Number, default: 100 },
t: { type: String, default: "km" }
}
}
},
created: {
type: Date,
default: Date.now
},
//Rating is an array of objects that consist of rateing 0-100 , job database id , comments from the Company
rating:
[
{
rate: Number,
jobId: Number,
jobComments: String
}
],
/*rating:
{
userTotalRating: {type: Number, default: 0},
ratingCounter : {type: Number, default: 0}
}*/
sensitive: {
cpr_cvr: String,
},
stripe: { type: String },
facebook: {},
linkedin: {},
log: {
updated: { type: Array, default: [] }
},
hashedPassword: String,
provider: { type: String, default: 'local' },
salt: String
});
UPDATE:
Mongodb version: 3.0.7
Turns out I just forgot to add the isAdmin field to my User Schema! Also, my call to the update was wrong, I changed it to this:
User.update({ email: targetUser.email }, { $set: { isAdmin: true }}, { $push: { 'log.updated': new Date() } }, function (err, user) {
if (err) {
responseObject.err = err;
responseObject.data = null;
responseObject.code = 422;
return res.json(responseObject);
}
return res.json(responseObject);
});
Thanks to everyone that put an effort to help me! :)
I encountered a similar problem. The solution was to add the callback.
This doesn't work:
Ride.updateOne({driver:req.body.id},{$set:{isBusy:true}});
This works:
Ride.updateOne({driver:req.body.id},{$set:{isBusy:true}},(e,s)=>{});
Try updating two fields with $set
User.update({ email: targetUser.email }, { $set: { isAdmin: true, 'log.updated': new Date() } }, function (err, user) {
if (err) {
responseObject.err = err;
responseObject.data = null;
responseObject.code = 422;
return res.json(responseObject);
}
return res.json(responseObject);
});
Hope it's works.
There is easier way to handle the issue. As per the documentation, the second parameter is the object where you can update the statement.
A.findByIdAndUpdate(id, update, options, callback)
So you just need to take everything inside the update object.
User.update({ email: targetUser.email, $set: {isAdmin: true}} // ... etc

Mongoose won't update sub-document

I've been banging my head against this for a few hours now and just can't seem to figure it out. I decided to use Mongo on a learning project to see how I like it. Mongoose came as the recommended way to use it, so I dove into that too. I have two schemas:
var PluginSchema = new Schema({
name: { type: String, required: true },
slug: { type: String },
description: { type: String },
created_date: { type: Date, default: Date.now },
active: { type: Boolean, default: true },
user: { type: Schema.Types.ObjectId, ref: 'User' },
versions: [PluginVersion.schema]
});
PluginSchema.methods.getLatestVersion = function(callback) {
if(this.versions.length > 0) {
this.versions.sort(function(a, b) {
if(semver.gt(a.version, b.version)) {
return 1;
} else if(semver.lt(a.version, b.version)) {
return -1;
} else {
return 0;
}
});
callback(this.versions[this.versions.length-1]);
} else {
callback(undefined);
}
};
and
var PluginVersionSchema = new Schema({
version: { type: String, required: true },
downloads: { type: Number, default: 0 },
size: { type: Number, required: true },
updatedChecks: { type: Number, default: 0 },
fileName: { type: String, required: true },
uploadedDate: { type: Date, default: Date.now }
});
The issue here is the 'versions' relationship. At some point I want to update a version of the Plugin. The thing I want to update is the updatedChecks field. Basically just updatedChecks += 1.
Plugin.findById(req.params.plugin_id)
.populate('user')
.populate('versions')
.exec(function(err, plugin) {
if(err) {
res.status(404);
res.send("Plugin not found.");
} else {
plugin.getLatestVersion(function(version) {
if(version !== undefined) {
pluginData = {
stuff: "that",
gets: "returned",
tothe: "user"
};
// This says 'Affected: 1'. As expected
PluginVersion.update({_id: version._id}, {
updatedChecks: version.updatedChecks + 1
}, function(err, affected) {
console.log("Affected: " + affected);
if(err) { res.send(err); }
res.status(200);
res.json(pluginData);
});
} else {
res.status(404);
res.send("No versions found for this plugin.");
}
});
}
});
So far, so good. However, when I try to access that version again via the Plugin schema, the updatedChecks value hasn't changed! I checked the _id value on the version I'm updating versus the version that gets pulled from the Plugin.versions field and they are they same. Do I need to remove the version from Plugin.versions and re-insert a new one with the updated value? I also tried just updating the value and calling save() but that didn't seem to work either.
I ended up getting this work by accessing the plugin version directly from the Plugin object.
var pluginIndex = false;
for(var i = 0; i < plugin.versions.length; i++) {
if(plugin.versions[i]._id === version._id) {
pluginIndex = i;
}
}
if(pluginIndex !== false) {
plugin.versions[pluginIndex].updatedChecks++;
plugin.versions[pluginIndex].markModified('updatedChecks');
plugin.versions[pluginIndex].save(function() {
plugin.markModified('versions');
plugin.save(function() {
res.status(200);
res.json(pluginData);
});
});
}
I also has a little help from: Mongoose save() not updating value in an array in database document
The problem here is, your updating query is written wrong. It must be
PluginVersion.update({
_id: version._id
}, {
$set: {
updatedChecks: version.updatedChecks + 1
}
}, function(...) {
...
});
or
PluginVersion.update({
_id: version._id
}, {
$inc: {
updatedChecks: 1
}
}, function(...) {
...
});
You can find more update operators here:
http://docs.mongodb.org/manual/reference/operator/update/

Resources