Mongoose findOneAndUpdate: Is there a way to update object in subdocument? - node.js

I have a model like this:
// Document
var programSchema = new Schema({
name: {
type: String
},
session: [sessionSchema]
}, {
timestamps: true
});
// Subdocument
var sessionSchema = new Schema({
name: {
type: String
},
info: {
type: String
},
order: {
type: Number
}
}, {
timestamps: true
});
Is there a way to access the subdocuments object and edit if exists, else create new?
I figured something like this:
router.post('/createsession', function (req, res) {
var options = { upsert: true, new: true, setDefaultsOnInsert: true };
var SessionData = req.body.session;
if (!SessionData.id) {
SessionData.id = mongoose.Types.ObjectId();
}
Program.findOneAndUpdate({ _id: req.body.session.id }, { $push: { session: SessionData } }, options, function (err, session) {
if (err) {
return res.status(409).json({
success: false,
message: 'Error creating/updating session'
});
} else {
return res.status(200).json({
success: true,
session: session
});
}
});
});
This only creates a new document. Would I be able to edit existing with this same query?

Try like this
var options = { upsert: true};
Program.findOneAndUpdate({ _id: req.body.session.id }, { $set: {
//Set individually values
name: req.nnae,
} },
options, function (err, session) {
if (err) {
return res.status(409).json({
success: false,
message: 'Error creating/updating session'
});
} else {
return res.status(200).json({
success: true,
session: session
});
}
});
});

Related

Mongoose populate with pagination

Trying to implement pagination on my populated query. I'm successful populating with mongoose populate but limit or skip doesn't work. Also tried mongoose-paginate library, pagination work but population not.
As an output I need only array of missions by user id that is paginated. Thank you.
User schema:
var mongoosePaginate = require('mongoose-paginate');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
unique: true,
required: true,
},
password: {
type: String,
required: true,
},
uavs: [uavSchema],
missions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Mission' }],
});
userSchema.plugin(mongoosePaginate);
This works but limit nor skip doesnt work
const getMissions = async (_id) => {
let missions = [];
try {
await User.findOne({ _id: _id })
.lean()
.populate('missions')
.then((usr) => {
console.log(usr);
Object.assign(missions, usr.missions);
});
return { success: true, missions };
} catch (err) {
return { success: false, err };
}
};
output when using mongoose populate
Then tried using mongoose-paginate
const getMissions = async (_id) => {
try {
var options = {
populate: 'missions',
page: 1,
limit: 4,
lean: true,
};
await User.paginate({ _id: _id }, options, function (err, result) {
console.log(result);
});
} catch (err) {
console.log(err);
}
};
output when using mongoose-paginate
Solution - searching missions colection
const getMissions = async (_id, page, limit) => {
try {
let missions = {};
var options = {
page,
limit,
lean: true,
};
await Mission.paginate({ _owner: _id }, options, function (err, result) {
Object.assign(missions, result);
});
return { success: true, missions };
} catch (err) {
return { success: false, err };
}
};

Mongoose update subarray item

I'm trying to update sub-array item in my collection , i'm trying to use set but can't get it work with _id , it only work when I say array[0] ...
Here is my method :
exports.updateSubCategory = (req, res) => {
const category = req.category;
Category.findById(category._id, function (err, doc) {
if (err) {
return res.status(400).json({
error: "Can't Find parent category",
});
} else {
doc.subcategory.set(0, { name: req.body.name }); works
doc.subcategory.set(req.body.id, { name: req.body.name });//doesn't work
doc.subcategory.set({_id:req.body.id}, { name: req.body.name });//doesn't work
doc.save((err, updatedCategory) => {
if (err) {
return res.status(400).json({
error: "Can't update subcategory",
});
}
res.json(updatedCategory);
});
}
});
};
My schema :
const mongoose = require("mongoose");
const categorySchema = new mongoose.Schema(
{
name: {
type: String,
trim: true,
required: true,
maxlength: 32,
unique: true,
},
subcategory: [
{
name: {
type: String,
trim: true,
required: true,
maxlength: 32,
unique: true,
},
},
],
},
{ timestamps: true }
);
module.exports = mongoose.model("Category", categorySchema);
solution :
exports.updateSubCategory = (req, res) => {
const category = req.category;
Category.findById(category._id, function (err, doc) {
if (err) {
return res.status(400).json({
error: "Can't Find parent category",
});
} else {
let subdoc = doc.subcategory.id(req.body.id);
subdoc.name = req.body.name;
doc.save((err, updatedCategory) => {
if (err) {
return res.status(400).json({
error: "Can't update subcategory",
});
}
res.json(updatedCategory);
});
}
});
};

How to display details in one to many relationship

In my case, one maincategory has many subcategories.
maincategory model defined:
const MainCategorySchema = mongoose.Schema({
mainCategoryName: {
type: String,
unique: true,
required: true,
},
});
subcategory model defined
const SubCategorySchema = mongoose.Schema({
subCategoryName: {
type: String,
unique: true,
required: true,
},
main_category: {
type: mongoose.Schema.Types.ObjectId,
ref: "MainCategory",
},
});
module.exports.getAllSubCategories = function (callback) {
SubCategory.find(callback);
};
route
router.get( "/subCategories",
passport.authenticate("jwt", { session: false }),
(req, res) => {
SubCategory.getAllSubCategories((err, subCategory) => {
if (err) {
let message = "No category";
return res.json({
success: false,
message,
});
} else {
return res.send(subCategory);
}
});
}
);
How can I display mainCategoryName along with subCategoryName?
You need to populate main_category like this:
router.get("/subCategories",
passport.authenticate("jwt", { session: false }), (req, res) => {
SubCategory.find()
.populate("main_category")
.exec((err, subCategory) => {
if (err) {
let message = "No category";
return res.json({
success: false,
message
});
} else {
return res.send(subCategory);
}
});
}
);

Instance Methods is not working in Sequelize

I can't seem to set the User model properly. I've implemented some instance methods that don't seem to be working
var UserDetails = mysequelize.sequelize.define('user_tb', {
id: {
autoIncrement: true,
type: mysequelize.sequelize.Sequelize.INTEGER,
allowNull: false,
},
username: {
type: mysequelize.sequelize.Sequelize.STRING,
primaryKey: true,
unique: true,
},
hierarchyid: {
type: mysequelize.sequelize.Sequelize.STRING
},
password: {
type: mysequelize.sequelize.Sequelize.STRING,
validate: {
len: {
args: [6, 15],
msg: "Please enter a password with at least 6 chars but no more than 15"
}
},
allowNull: false
},
customerid: {
type: mysequelize.sequelize.Sequelize.INTEGER
},
statususer: {
type: mysequelize.sequelize.Sequelize.STRING,
allowNull: false
},
userid: {
unique: true,
type: mysequelize.sequelize.Sequelize.STRING,
allowNull: false
},
authtoken: {
unique: true,
type: mysequelize.sequelize.Sequelize.STRING,
allowNull: false
}
},
{
tableName: 'user_tb',
timestamps: false,
freezeTableName: true
});
UserDetails.prototype.toJSON = function(){
var user = this;
var userObject = user.toObject();
return _.pick(userObject,['userid','password']);
};
UserDetails.prototype.findByCredentials = function(userid, password)
{
console.log('Sunddep');
var User = this;
// return User.fin
User.findOne({userid}).then((user)=> {
if(!user)
{
return Promise.reject();
}
return new Promise((resolve,reject) => {
bcrypt.compare(password,user.password,(err,res) => {
if(res)
{
resolve(user);
}
else{
reject();
}
})
})
});
}
UserDetails.prototype.generateAuthToken = function()
{
var user = this;
var access = 'authtoken';
var token = jwt.sign({userid:
user.userid.toHexString(),access},process.env.JWT_SECRET).toString();
user.build({
access: token
});
user.save().then(() =>{
return token;
});
}
module.exports = {UserDetails}
server.js
app.post('/user/login', (req, res) => {
console.log(req.body);
var body = _.pick(req.body, ['userId', 'password']);
user.findByCredentials(body.userId, body.password).then(() => {
res.send('Sundeep');
},
(e) => {
sendData: ({
wsState: '0',
messageCode: 'WS000001',
message: 'No user find with this Id',
userData: []
});
res.status(400).send(sendData)
});
});
Hi, I am getting error while calling instance method from other class. Can any one tell me how can i achieve it
UserDetails.prototype.findByCredentials = function(userid, password) {.....}
But while run the server.js file i getting error like UserDetails.findByCredentials is not a function while calling from other class
Thanks for help in advance.

How to implement a follow system, return a list of followers and following users

In my application there are 4 features I need to implement:
A user can follow another user.
A user can unfollow another user.
A user can see a list of all of their followers.
A user can see a list of all whom they are following.
I believe I have implemented 1. and 2. correctly. I created a follow schema as you can see below in my follow.model and I have created follow.controller with two methods, to store (follow) and destroy (unfollow).
Now I want to to implement 3. and 4. I created two arrays in the user.model schema, one for following and one for followers. When I return the user in my user.controller, how do I populate the following and followers array? At the moment they are empty.
follow.model.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var FollowSchema = new Schema({
follower: {
type: Schema.Types.ObjectId,
ref: 'User'
},
followee: {
type: Schema.Types.ObjectId,
ref: 'User'
}
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
module.exports = mongoose.model('Follow', FollowSchema);
follow.controller.js
'use strict';
const User = require('../models/user.model');
const Follow = require('../models/follow.model');
class FollowController {
constructor() {
}
store(req, res) {
let follower = req.body.follower;
let followee = req.params.id;
let follow = new Follow({
follower: follower,
followee: followee,
});
follow.save(function (err) {
if (err) {
return res.status(404).json({
succes: false,
status: 404,
data: {},
message: "There was an error trying follow the user."
});
}
return res.status(200).json({
success: true,
status: 200,
data: follow,
message: 'Successfully followed user'
});
});
}
destroy(req, res) {
let follower = req.params.followerid;
let followee = req.params.id;
Follow.remove({ 'follower': follower, 'followee': followee }, (err, result) => {
if (err) {
return res.status(404).json({
success: false,
status: 404,
data: {},
message: "Error removing record"
});
}
return res.status(201).json({
success: true,
status: 201,
data: {},
message: "Successfully unfollowed user"
})
});
}
}
module.exports = FollowController;
user.model.js
let UserSchema = new Schema({
email: {
address: {
type: String,
lowercase: true,
//unique: true,
},
token: String,
verified: {
type: Boolean,
default: false,
},
},
password: {
type: String,
},
following: [{
type: Schema.Types.ObjectId, ref: 'Follow'
}],
followers: [{
type: Schema.Types.ObjectId, ref: 'Follow'
}],
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
user.controller.js
show(req, res) {
let id = req.params.id;
User.findOne({ '_id': id },
function (err, user) {
if (err) {
return res.json(err);
}
return res.json(user);
});
}
You just need to populate these fields:
User.findOne({ '_id': id }, (err, user) => {
if (err) return res.json(err);
return res.json(user);
}).populate([
{ path: 'following' },
{ path: 'followers' }
]);

Resources