Why is my mongoose populate not retrieving the nested array? - mongodb

I have the following mongoose schemas:
const CategoriesSchema = new mongoose.Schema(
{
sites: [
{
site: {
type: ObjectId,
ref: "Sites",
}
}
],
);
mongoose.model("Categories", CategoriesSchema, 'organizer-categories');
And:
const SitesSchema = new Schema({
url: {
type: String,
required: true,
},
img: {
type: String,
},
});
mongoose.model("Sites", SitesSchema, "organizer-sites");,
The following function is supposed to create a new site in mongodb, add the site to Categories as shown in the schema and return the updated category with the new site data using mongoose's populate method. But only the _id of site is being returned with the category data.
exports.addSite = async (req, res) => {
const {categoryId, siteUrl} = req.body;
console.log('categoryId, siteUrl', categoryId, siteUrl)
try {
let site = await Sites.findOne({url: siteUrl});
console.log('site', site)
if(site) {
return res.status(422).send(`${siteUrl} already exists.`)
}
site = await Sites.create({url: siteUrl, categoryId});
// site = {url: siteUrl, categoryId};
const category = await Categories.findOneAndUpdate({
_id: categoryId
}, {
$addToSet: {
sites: site
}
}, {
new: true
}).populate({
path: 'sites.site',
model: 'Sites'
})
console.log('category', category)
res.status(201).json(category);
} catch(error) {
console.error(error);
return res.status(500).send('Error adding category.')
}
}

Related

How to update a user profile which has a property which is a ref in MongooseJS?

I have a User schema which has reference to a profile schema.
const UserSchema = new Schema(
{
_id: mongoose.Schema.Types.ObjectId,
email: {
....email props...
},
password: {
...password props...
},
profile: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Profile",
}],
},
);
const Profile = new Schema({
_user: {
type: Schema.Types.ObjectId, ref: 'User'
},
'displayName': {
type: String,
default: ''
},
'interestedActivities': ['Ping-pong'], <---- This bad boy/girl is an array
'memberSince': { type: Date, default: Date.now }
}
)
I'd like to create a route which can update the User properties AND the Profile properties in one shot—with a caveat one of the properties on the Profile model is an array!!!
I tried this....
handler
.use(auth)
.put((req, res, next) => {
emailValidator(req, res, next, 'email');
},
async (req, res, next) => {
await connectDB()
const {
profileDisplayName,
profileEmail,
interestedActivities } = req.body;
const update = {
email: profileEmail,
'profile.$.displayName': profileDisplayName,
'profile.$.interestedActivities': interestedActivities
}
const filter = { _id: req.user.id };
const updatedUser = await User.findOneAndUpdate(filter, update, { new: true })
try {
console.log("updatedUser ", updatedUser);
if (updatedUser) {
return res.status(200).send({
updatedUser,
msg: `You have updated your profile, good job!`
});
}
} catch (error) {
errorHandler(error, res)
}
})
export default handler;
My response is:
Status Code: 500 Internal Server Error
Cast to ObjectId failed for value "[
{
id: 'ae925393-0935-45da-93cb-7db509aedf20',
name: 'interestedActivities',
value: []
}
]" (type Array) at path "profile.$"
Does anyone know how I could also afford for the property which is an array?
Thank you in advance!

Adding multiple items to mongodb

I have this schema with
const userSchema = new mongoose.Schema(
{
skills: [{ name: { type: String, unique: true }, level: { type: Number } }],
and I am trying, after getting an array of objects from the client, to add all of them at once under a user in MongoDB
my old implementation when it was only an array is this one below. I have no idea how to go about it now tho. Could anyone help me?
const { email } = session;
const { skill } = req.body;
if (req.method === 'POST') {
try {
const user = await User.findOne({ email });
const updatedUser = await User.findOneAndUpdate(
{ email },
{ skills: [...user.skills, { name: skill }] }
);
const { email } = session;
// object from the client
const { skills } = req.body;
if (req.method === 'POST') {
try {
const updatedUser = await User.findOneAndUpdate(
{ email },
{ $set: {skills} }
);
the best is getting the array correctly formatted from front-end, if not use a map before call findOneAndUpdate

Delete object from inner schema in mongoose?

How do I delete object from inner schema in mongoose?
I try to delete comments from the Holiday Schema, this is the holiday schema:
const holidaySchema = new mongoose.Schema(
{
comments: [commentSchema],
},
)
const Holiday = mongoose.model("Holiday", holidaySchema);
export default Holiday;
and this is the comments schema:
const commentSchema = new mongoose.Schema(
{
action: { type: String },
time: { type: String },
name: { type: String },
image: { type: String },
content: { type: String },
rating: { type: Number },
},
{
timestamps: true,
}
);
I try to delete a specific comment from the holidaySchema in this way:
holidayRouter.delete(
"/:id/comments/:commentId",
isAuth,
expressAsyncHandler(async (req, res) => {
const holiday = await Holiday.updateOne(
{ _id: req.params.id },
{ $pull: { comments: { _id: req.params.commentId } } }
);
if(holiday){
console.log(holiday);
}
})
);
the console:
and this is not working, do you know what I am doing wrong or what should I do?
thank you
Mongoose converts the object into json, and we can customize that json which is returned.
commentSchema.methods.toJSON = function(){
const commentSchema = this.toObject()
delete commentSchema.name
delete commentSchema.rating
return commentSchema
}
New the JSON which is returned will not have name and rating.

How to insert auto increment number in mongoose

Tried to insert auto increment number for serial number in mongodb using mongoose and nodejs but not working.Where i want to update my code to find solution.If anyone knows please help to find solution.
subs.model.js:
const mongoose = require('mongoose');
var subscriberSchema = new mongoose.Schema({
_id: {type: String, required: true},
email: {
type: String
}
}, {
versionKey: false,
collection: 'subscribers'
});
module.exports = mongoose.model('Subscribers', subscriberSchema);
data.controller.js:
module.exports.subscribeMail = (req, res, next) => {
var subscribeModel = mongoose.model("Subscribers");
var subscribemailid = req.query.email;
var subscribe = new subscribeModel({
email: subscribemailid
});
var entitySchema = mongoose.Schema({
testvalue: { type: String }
});
subscribe.save(function(error, docs) {
if (error) { console.log(error); } else {
console.log("subscribe mail id inserted");
console.log(docs)
res.json({ data: docs, success: true });
}
});
entitySchema.pre('save', function(next) {
var doc = this;
subscribe.findByIdAndUpdate({ _id: 'entityId' }, { $inc: { seq: 1 } }, function(error, counter) {
if (error)
return next(error);
doc.testvalue = counter.seq;
next();
});
});
};
If i use above code inserting data into mongodb like below:
_id:5f148f9264c33e389827e1fc
email:"test#gmail.com"
_id:6f148f9264c33e389827e1kc
email:"admin#gmail.com"
But i want to insert like this
_id:5f148f9264c33e389827e1fc
serialnumber:1
email:"test#gmail.com"
_id:6f148f9264c33e389827e1kc
serialnumber:2
email:"admin#gmail.com"
You can use this plugin: https://www.npmjs.com/package/mongoose-auto-increment
First you need to initialize it after creating Mongoose connection:
const connection = mongoose.createConnection("mongodb://localhost/myDatabase");
autoIncrement.initialize(connection);
Than in your subs.model.js file:
const mongoose = require('mongoose');
const autoIncrement = require('mongoose-auto-increment');
var subscriberSchema = new mongoose.Schema({
_id: {type: String, required: true},
email: {
type: String
}
}, {
versionKey: false,
collection: 'subscribers'
});
subscriberSchema.plugin(autoIncrement.plugin, {
model: 'Subscribers',
field: 'serialnumber'
});
module.exports = mongoose.model('Subscribers', subscriberSchema);

How create relationship between two collections

I'm creating server app using nodejs(express) and mongodb(mongoose). I must create relationships between Organization model and Users model. After creating an organization, I want to create a user that will apply to a specific organization. One user can apply to many organizations. How can I do this?
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// UserShema
const UserSchema = Schema({
login: {
type: String,
require: true,
unique: true
},
password: {
type: String,
require: true
},
organization: {
ref: "Organization",
type: Schema.Types.ObjectId
}
});
// Organization Schema
const OrganizationSchema = Schema({
label: {
type: String
},
users: [{
type: Schema.Types.ObjectId,
ref: "Users"
}]
});
//For now I have simple route for creating an Organization.
// request:
// {
// "label": "testOrg"
// }
exports.createOrganization = async (req, res) => {
try {
const org = await new Organization(req.body);
await org.save();
} catch (error) {
return res.status(500).json({error})
}
}
//And I have this route for user registration
exports.signup = async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
};
const {login} = req.body;
try {
const checkUser = await Users.findOne({login});
if (!checkUser) {
const user = await new Users(req.body);
await user.save();
return res.status(200).json({ user });
} else {
return res.status(400).json({error: "User already exist"})
}
} catch (error) {
return res.status(500).json({error})
}
};
You could embed the organization id into a string into the user document
Like this {
name: "Name",
location: "CA",
organizations: [123456789, 234567890, ...]
}