remove referencing objects on deletion from array in MongoDB - node.js

I have 2 schemas User and Restaurant, and user has an array of restaurants, am trying to reach when deleting the restaurant delete its reference from user automatically, am trying to reach it with the model.pre('remove')..but when I delete a restaurant the reference id it still exist in User.
Here is my User Schema:
const userSchema = new Schema(
{
email: {
type: String,
trim: true,
// required: true,
unique: true,
},
password: {
type: String,
// required: true,
min: 5,
},
stripeCustomerId: {
type: String,
// unique: true,
},
linkedAffiliateUser: {
type: String, //mongoose.Schema.Types.ObjectId,
},
restaurants: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Restaurant",
},
],
role: {
roleId: { type: Number, minlength: 1, maxlength: 1, required: true },
roleName: { type: String, trim: true, required: true },
},
// seperated schema
},
{ timestamps: true }
);
export default mongoose.model("User", userSchema);
and here is my Restaurant Schema:
const restaurantSchema = new Schema({
restaurantOwner: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
Name: {
type: String,
trim: true,
},
server: { type: mongoose.Schema.Types.ObjectId, ref: "ServerUser" },
restaurantLinkAccess: {
type: String,
required: true,
trim: true,
unique: true,
},
});
restaurantSchema.pre("remove", function (next) {
this.model("User")
.update(
{ restaurantSchema: this },
{ $pull: { comments: this._id } },
{ multi: true }
)
.exec(next);
});
export default mongoose.model("Restaurant", restaurantSchema);
I also tried to solve it like this:
restaurantSchema.pre("remove", function (next) {
this.model("User").remove({ $pull: { restaurants: this._id } }, next);
});
Please help.

Related

How to get a certain field of an embedded MongoDB document knowing its ObjectId

I have two collections in MongoDB database, Post and User. Each post contains the creator's ObjectId. When fetching all posts from the database, I want to add the name information, which is a field of User/creator. I tried to access the name field by post.creator.name, but it is not working.
const postSchema = new Schema(
{
title: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
imageUrl: {
type: String,
required: true,
},
creator: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
},
},
{ timestamps: true }
);
const userSchema = new Schema({
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
status: {
type: String,
required: true,
},
isExpert: {
type: Boolean,
required: true,
},
posts: [
{
type: Schema.Types.ObjectId,
ref: "Post",
},
],
});
exports.getPosts = (req, res, next) => {
Post.find({}).then((posts) => {
const postsWithAuthorName = posts.map(post => {
return {
...post,
name: post.creator.name
}
})
res.status(200).json({
posts: postsWithAuthorName,
});
});
};
Try this
Post.find({}).populate('creator', 'name')
See populate doc for reference.
When you query posts, creator is just an ObjectId, so you can't just call .name on it. To make it work you need to lookup this data by using e.g. populate.

How to use values of map function in other functions?

I want to use data returned by a map method into another function.
Here is the route schema:
const routeSchema = new mongoose.Schema(
{
Location: {
from: {
type: mongoose.Schema.Types.ObjectId,
ref: "Location",
required: true,
},
to: {
type: mongoose.Schema.Types.ObjectId,
ref: "Location",
required: true,
},
},
busId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Bus",
required: true,
},
date: {
type: String,
required: true,
},
departureTime: {
type: Number,
required: true,
},
arrivalTime: {
type: Number,
required: true,
},
},
{
timestamps: true,
}
);
and here is the booking schema and in booking table routeId is embedded:
const bookingSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
routeId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Route",
required: true,
},
passengers: [
{
name: { type: String, required: true, trim: true },
gender: { type: String, required: true, trim: true },
age: { type: Number, required: true, trim: true },
}],
phone: {
type: Number,
required: true,
},
email: {
type: String,
required: true,
},
bookingDate: {
type: String,
required: true,
},
fare: {
type: Number,
required: true,
},
seats: {
type: [Number],
required: true,
},
departureDetails: [
{
city: { type: String, required: true, trim: true },
location: { type: String, required: true, trim: true },
time: { type: String, required: true, trim: true },
date: { type: String, required: true, trim: true },
},
],
arrivalDetails: [
{
city: { type: String, required: true, trim: true },
location: { type: String, required: true, trim: true },
time: { type: String, required: true, trim: true },
date: { type: String, required: true, trim: true },
},
],
},{
timestamps:true
});
Here is the map function method:
router.get("/trip/single", async (req, res) => {
if (!req.query.from || !req.query.to || !req.query.date) {
return res.send({
error: "Please enter the data to get the trip",
});
}
const { from, to, date } = req.query;
const routes = await Route.find({
"Location.from": from,
"Location.to": to,
"date": date.toString(),
});
const matchedBus = await routes.filter(() =>{
return Route.busId === routes._id
});
const bookings = await Booking.find({
routeId: { $in: matchedBus.map((matchedBus) => matchedBus._id) },
});
console.log(bookings);
const busIdWithSeatsObj = {};
var busData = matchedBus.map(data => data)
console.log(busData);
This busData console is returning this data:
[
{
Location: {
from: new ObjectId("6295f0986f9e32990d8b3488"),
to: new ObjectId("6295f0c06f9e32990d8b348b")
},
_id: new ObjectId("6295f12c6f9e32990d8b348e"),
busId: new ObjectId("6295f0836f9e32990d8b3485"),
date: '2022-06-02',
departureTime: 11,
arrivalTime: 6.3,
createdAt: 2022-05-31T10:42:52.785Z,
updatedAt: 2022-05-31T10:42:52.785Z,
__v: 0
}
]
Now I want to use only busId and date only in the function below:
for (let i = 0; i < matchedBus.length; i++) {
let currentBusSeats = [];
const busBookings = bookings.filter((booking) => {
return (
//Want to use date and busId data in here
//someData === date.toString() &&
//someData === matchedBus[i]._id
);
});
console.log(busBookings);
busBookings.forEach(() => {
currentBusSeats = [...currentBusSeats, ...Booking.seats];
});
busIdWithSeatsObj[matchedBus[i]._id] = currentBusSeats;
}
res.status(200).send({ routes, matchedBus, busIdWithSeatsObj });
});
How can I do that to get the result?
var busData = matchedBus.map(data => data
'use your for loop inside data and you can get you _id value by data._id'
)

Find matched data from object in mongoose

I want to get all matched data from an object but I am getting an empty array.
Here is the location table:
const locationSchema = new mongoose.Schema(
{
location: {
name: {
type: String,
unique: true,
required: true,
lowercase: true,
},
subLocation: [String],
},
},
{
timestamps: true,
}
);
and it is embedded in route table:
const routeSchema = new mongoose.Schema(
{
location: {
from: {
type: mongoose.Schema.Types.ObjectId,
ref: "Location",
required: true,
},
to: {
type: mongoose.Schema.Types.ObjectId,
ref: "Location",
required: true,
},
},
busId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Bus",
required: true,
},
date: {
type: String,
required: true,
},
departureTime: {
type: Number,
required: true,
},
arrivalTime: {
type: Number,
required: true,
},
},
{
timestamps: true,
}
);
Now I am running query to get the matched data from route table but I am getting an empty array.
http://127.0.0.1:3000/trips?from=6295871d69217e9c28cf7f19&to=6295874869217e9c28cf7f1c&date=2022-06-02
here is the query :
router.get("/trips", async (req, res) => {
if (!req.query.from || !req.query.to || !req.query.date) {
return res.send({
error: "Please enter the data to get the trip",
});
}
const { from, to, date } = req.query;
const routes = await Route.find({
from,
to,
date,
});
Another Question:
I am passing an Id as a value now I want to pass value as a sting like this: from=Mumbai&to=Ahmedabad&date=2022-06-02.
How to do that? because whenever I do that I am getting a casting error
I suggest you to change the location schema to have from and to locations separately like below.
const locationSchema = new mongoose.Schema(
{
fromLocation: {
name: {
type: String,
unique: true,
required: true,
lowercase: true,
},
subLocation: [String],
},
toLocation: {
name: {
type: String,
unique: true,
required: true,
lowercase: true,
},
subLocation: [String],
},
},
{
timestamps: true,
}
);
Thus the route schema should look like this
const routeSchema = new mongoose.Schema(
{
location: {
type: mongoose.Schema.Types.ObjectId,
ref: "Location",
required: true,
},
date: {
type:String,
required: true
},
....
....
And then do something like this...
let locations = await Location.find({
'fromLocation.name': from,
'toLocation.name': to,
});
After that
const ids = locations.map(location => location._id)
const routes = await Route.find({$and: [{location : {$in: ids}},{date}]});
const route = routes.find(()=>{
return ([{ date }, { routes }])
});

MongoDB mongoose filter with gender where user in profile is objectID

I am new in backend development.
I am trying to create profile endpoints to get all profiles with the gender of the user is either male or female.
Profile contains user as a objectID.
I want to filter profiles using users gender.
My UserSchema looks like this
const userSchema = mongoose.Schema(
{
firstname: {
type: String,
required: true,
trim: true,
},
lastname: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
required: true,
unique: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Invalid email');
}
},
},
password: {
type: String,
required: true,
trim: true,
minlength: 8,
validate(value) {
if (!value.match(/\d/) || !value.match(/[a-zA-Z]/)) {
throw new Error('Password must contain at least one letter and one number');
}
},
private: true, // used by the toJSON plugin
},
role: {
type: String,
enum: roles,
default: 'user',
},
gender: {
type: String,
enum: genders,
required: true,
},
profileStatus: {
type: String,
enum: profileStatus,
default: 'inProgress',
},
isEmailVerified: {
type: Boolean,
default: false,
},
},
{
timestamps: true,
}
);
And Profile schema looks like this
const profileSchema = new Schema(
{
user: { type: Schema.Types.ObjectId, ref: 'User', required: true, unique: true },
bio: { type: String, required: true },
profilePicUrl: {
type: String,
required: true,
},
birthdate: {
type: Date,
required: true,
},
profession: {
type: String,
required: true,
},
profileCompletion: {
type: Number,
default: 50,
min: 0,
max: 100,
},
credits: {
type: Number,
default: 2,
min: 0,
},
lastLogin: {
type: Date,
default: new Date(),
required: true,
},
},
{ timestamps: true }
);
I want to find profiles where user gender is male or female.
How can I do that?
You can create a endpoint like this and use .find() to find all the users with the gender passed by user
router.get(/user/:gender, async (req, res) => {
try {
const users = await User.find({ gender: req.params.gender }).exec();
res.status(200).json(users);
} catch (err) {
return res.status(500);
}
})

Add data in an array of object with mongoDB

I need your help, I try to add(if it not exists) or update if exists datas in an array of Object in MongoDB.
Here is my Model
import { Schema, model } from "mongoose";
const userSchema = new Schema({
firstName: {
type: String,
required: true,
unique: false,
trim: true
},
pseudo: {
type: String,
required: true,
unique: true,
trim: true,
minlength: 3
},
email: {
type: String,
required: false,
trim: true
},
password: {
type: String,
required: true
},
// password2: {
// type: String,
// required: true
// },
tags: {
type: Array,
required: false
},
address: {
type: String,
required: true,
unique: false,
trim: true
},
coord: {
type: Object,
required: false,
unique: false,
trim: true
},
poll: [
{
tag: String,
dates: Array
}
]
},
{
timestamps: true,
});
const User = model('User', userSchema);
export default User;
My route
router.route('/calendar/:email').post((req, res) => {
User.findOne({ email: req.body.email }).then( (user) =>{
console.log("user 1", user)
User.bulkWrite([
{
insertOne: {
"poll": {
"tag": req.body.selectedTag,
"dates": req.body.datesArray
}
}
},
{
updateOne: {
"filter": {
"tag" : req.body.selectedTag
},
"update": {
$set: {
"dates": req.body.datesArray
}
},
}
}
])
})
});
and the datas sended :
email: 'john#gmail.com',
selectedTag: 'work',
dateArray: [ '2020-07-16T22:00:00.000Z' ]
I try many things like by findOneaAndUpdate, but I don't know how to add in the array "poll", objects with tag and the dates associated.
If somebody could help me it would be very nice !
I shoul use add $addToSet or $push, depending if the element is unique or not.
Something like this:
"update": {
"$addToSet": {
"poll": { /*...*/ }
}
}
For reference:
http://docs.mongodb.org/manual/reference/operator/update/addToSet/
http://docs.mongodb.org/manual/reference/operator/update/push/

Resources