how to compare document from 3 different collections - javascript

I have three collections named employees, leaves, events in my mongodb database. I want to fetch employees who are not on vacation nor have an event scheduled on a specific date.
employees Model
const employeeSchema = new mongoose.Schema({
name: { type: String, required: true },
role: {
type: String,
required: true,
},
image: { type: String, required: false },
phoneNumber: {
type: Number,
required: true,
},
email: {
type: String,
default: null,
required: \[true, "Email is required"\],
},
empType: {
type: String,
required: true,
},
password: { type: String, required: true },
lastLogin: { type: Date, default: null },
token: { type: String, default: null },
deviceId: { type: Array, default: null },
});
Events model
const eventsSchema = new mongoose.Schema({
venue: { type: String, required: true },
eventType: { type: String, required: true },
eventDate: { type: Date, required: true },
startTime: { type: Date, required: true },
departureTime: { type: Date, required: true },
numberOfCameras: { type: Number, required: true },
numberOfDays: { type: Number, required: true },
packagePrice: { type: Number, required: true },
teamLead: { type: String, required: true },
teamList: { type: Array, required: true },
teamMembers: [],
});
leaves model
userId: { type: mongoose.ObjectId, required: true },
startDate: { type: Date, required: true },
endDate: { type: Date, required: true },
reason: { type: String, required: true },
leaveSeekerName: { type: String, required: true },
leaveSeekerRole: { type: String, required: true },
status: { type: String, default: "pending" },
},
{
timestamps: true,
}
so i am want to get employee who are not on leave nor assigned an event on specified date

The question is not completed.
First, you should complete the linked relationship among the 3 tables.
If your 3 schemas use _id in employees and teamMember of events, userId in leaves to tag someone as the same person on the below.
const employeeSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
role: {
type: String,
required: true,
},
image: {
type: String,
required: false
},
phoneNumber: {
type: Number,
required: true,
},
email: {
type: String,
default: null,
required:true,
},
empType: {
type: String,
required: true,
},
password: {
type: String,
required: true
},
lastLogin: {
type: Date,
default: null
},
token: {
type: String,
default: null
},
deviceId: {
type: Array,
default: null
},
});
const eventsSchema = new mongoose.Schema({
venue: {
type: String,
required: true
},
eventType: {
type: String,
required: true
},
eventDate: {
type: Date,
required: true
},
startTime: {
type: Date,
required: true
},
departureTime: {
type: Date,
required: true
},
numberOfCameras: {
type: Number,
required: true
},
numberOfDays: {
type: Number,
required: true
},
packagePrice: {
type: Number,
required: true
},
teamLead: {
type: String,
required: true
},
teamList: {
type: Array,
required: true
},
teamMembers: [
{
_id:mongoose.ObjectId,
name: String,
}
],
});
const leaveSchema = new mongoose.Schema({
userId: {
type: mongoose.ObjectId,
required: true
},
startDate: {
type: Date,
required: true
},
endDate: {
type: Date,
required: true
},
reason: {
type: String,
required: true
},
leaveSeekerName: {
type: String,
required: true
},
leaveSeekerRole: {
type: String,
required: true
},
status: {
type: String,
default: "pending"
},
}, {
timestamps: true,
})
You can consider use aggregations like this:
db.employees.aggregate( [
{
"$lookup": {
"from": "events",
"localField": "teamMembers._id",
"foreignField": "_id",
"as": "events"
}
},
{
"$lookup": {
"from": "leaves",
"localField": "_id",
"foreignField": "userId",
"as": "leaves"
}
},
{
"$match": {
"$and": [
{
"events.startTime": {
"$lte": nowTime
},
"events.departureTime": {
"$gte": nowTime
},
"leves.startDate": {
"$lte": nowDate
},
"leaves.endDate": {
"$gte": nowDate
}
}
]
}
}
] )
You may need to adjust the value of nowTime and nowDate.

Related

Can't filter by a nested populated item

I'm using mongoose-paginate-v2 for my TransactionModel.
I can't seem to filter by the user name or email.
If I don't use any query the docs return with the populated objects, like the user's name, and email, so I believe the issue is with the filter variable.
I want to keep using mongoose-paginate-v2
const transactionSchema: Schema = new Schema(
{
user: { type: Types.ObjectId, ref: CollectionNames.user, required: false },
subscription: { type: Types.ObjectId, ref: CollectionNames.subscription, required: false },
paidAt: { type: Date, required: true, default: new Date() },
amount: { type: Number, required: true },
currency: { type: String, required: true, default: CurrencyCodes.USD },
status: { type: String, required: true, default: TransactionStatuses.pending },
refundedAt: { type: Date, required: false },
refundAmount: { type: Number, required: false },
provider: { type: String, required: true },
providerTransactionId: { type: String, required: true },
invoiceLink: { type: String, required: false },
referral: { type: referralSchema, required: false },
eventsHistory: { type: [String], required: false, default: [] }
},
{
timestamps: true
}
);
// The function body:
const { page, limit, query: searchQuery } = query;
const options = {
page: page || 1,
limit: limit || 10,
sort: {
createdAt: -1
},
populate: [
{
path: 'user',
select: 'name socialAccounts email lastLoginEmail notificationEmail'
},
{
path: 'referral',
select: 'user commission payoutExpectedAt paidAt status'
}
],
lean: true
};
const filter = {};
if (searchQuery) {
const searchQueryRegex = new RegExp(searchQuery, 'i');
Object.assign(filter, {
$or: [
{
providerTransactionId: {
$regex: searchQueryRegex
}
},
{
'user.name': {
$regex: searchQueryRegex
}
},
{
'user.email': {
$regex: searchQueryRegex
}
},
]
});
}
const { docs, totalDocs, totalPages, hasNextPage } = await TransactionModel.paginate(filter, options);

MongoDB (mongoose) filter with value in array with reference

I am trying to filter an array in a document in mongoose.
The problem i am having is trying to filter with a value in the array that is in the reference.
To clarify, i have a document containg all the information about a course. In that course i have a array of objects that contains information about students. An object containts a status and also a refrence to the actual user object. I would like filter the students array with a value found in the refrence.
The way i have tested this is as following:
courseModel.findOne({ _id: courseId, 'students.user.startDate': { $lte: startDate } });
My models look like this:
CourseModel:
{
name: {
type: String,
required: true,
maxlength: 50,
minlength: 2,
trim: true
},
description: {
type: String,
required: false,
maxlength: 500,
trim: true
},
type: {
type: String,
required: true,
enum: ['physical', 'online', 'quiz']
},
color: {
type: String,
required: true,
match: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
},
events: [
{
type: Schema.Types.ObjectId,
ref: 'event'
}
],
questions: [
{
type: Schema.Types.ObjectId,
ref: 'question'
}
],
educators: [
{
type: Schema.Types.ObjectId,
ref: 'user'
}
],
students: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
status: {
type: String,
enum: ['notBooked', 'booked', 'attended', 'completed']
},
lastSlackMessage: {
ts: {
type: String
},
channel: {
type: String
}
},
events: [
{
type: Schema.Types.ObjectId,
ref: 'event'
}
]
}
],
teams: [
{
type: Schema.Types.ObjectId,
ref: 'team'
}
],
createdBy: {
type: Schema.Types.ObjectId,
ref: 'user'
},
updatedBy: {
type: Schema.Types.ObjectId,
ref: 'user'
}
}
UserModel:
{
name: {
type: String,
required: true,
maxlength: 100,
trim: true
},
email: {
type: String,
required: true,
minlength: 5,
match: /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
},
employeeId: {
type: String,
required: true
},
slackId: {
type: String,
default: ''
},
teams: [
{
type: Schema.Types.ObjectId,
ref: 'team'
}
],
questions: [
{
question: {
type: Schema.Types.ObjectId,
ref: 'question'
},
status: {
type: String,
enum: ['answered', 'pending', 'notSent']
},
tries: {
type: Number,
default: 0
}
}
],
startDate: {
type: Date,
required: true
}
}
I appreciate any help i can get, thank you!

How to get only matched data in mongoose (node.js)?

I am building a bus ticket booking app in node.js. I want to fetch only related data about queries not all the data But I am getting all the data about Bus.
Here is the location model. only admin can enter data about locations.
const locationSchema = new mongoose.Schema(
{
departureLocation: {
name: {
type: String,
required: true,
lowercase: true
},
time: {
type: String,
required: true,
},
subLocations: { type: [String], lowercase: true },
},
arrivalLocation: {
name: {
type: String,
required: true,
lowercase: true
},
time: {
type: String,
required: true,
},
subLocations: { type: [String], lowercase: true },
},
},
{
timestamps: true,
}
);
Here is the route table. Again admin...
const routeSchema = new mongoose.Schema({
location:{
type: mongoose.Schema.Types.ObjectId,
ref: 'Location',
required: true
},
duration: {
type: Number,
required: true
},
date: {
type:String,
required: true
},
},
{
timestamps: true,
});
Bus model: Admin...
const busSchema = new mongoose.Schema({
busNumber: {
type: String,
unique: true,
required: true,
},
seats: {
type: Number,
},
route: {
type: mongoose.Schema.Types.ObjectId,
ref: "Route",
required: true,
},
},
{
timestamps: true,
});
and here finally the booking table:
const bookingSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
busId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Bus",
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: {
required: true,
type: [Number],
},
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
});
Whenever an authorized user enters the booking data It is getting saved to the database. No problem whatsoever
Now I want to show every user(Non-authorized as well) of my app about trips(routes), the bus which will run on that particular trip and reserved and available seats in that particular bus which is currently stored.
But the problem is that I am getting all the buses even if it is not on that trip.
here is the query:
router.get("/trip/single", async (req, res) => {
if (!req.query.departure || !req.query.arrival || !req.query.date) {
return res.send({
error: "Please enter the data to get the trip",
});
}
const { departure, arrival, date } = req.query;
let locations = await Location.find({
'departureLocation.name': departure,
'arrivalLocation.name': arrival,
});
const ids = locations.map(location => location._id)
const routes = await Route.find({$and: [{location : {$in: ids}},{date}]});
const route = routes.find(()=>{
return ([{ date }, { routes }])
});
let buses = await Bus.find({})
let matchedBuses = buses.filter((bus)=> {
return bus.routes === locations._id
})
const bookings = await Booking.find({})
const busIdWithSeatsObj = {}
for(let i = 0; i < matchedBuses.length; i++){
let currentBusSeats = []
const busBookings = bookings.filter((booking) => {
return (booking.departureDetails.date === date &&
booking.busId.toString() === matchedBuses[i]._id.toString()
)
})
busBookings.forEach((booking) => {
currentBusSeats = [...currentBusSeats, ...booking.seats]
})
busIdWithSeatsObj[matchedBuses[i].seats] = currentBusSeats
}
res.status(200).send({route, matchedBuses, busIdWithSeatsObj});
});
Now I also want to fetch details by Id(only single bus).
How to do that?
Can anyone help me out here?
here's the input data image with result for date: 2022-06-02 which is actually available in the database : https://i.stack.imgur.com/FlfaG.png
This is the second query with result for date: 2022-06-01. It is not available in the database still showing matchedBus.: https://i.stack.imgur.com/xY5pW.png Now route data is gone but matched buses still shows.

mongo query $near always 0 results

My search Position is the same as the position in the database. The result is an empty array. I expected to get the one element from database, because the distance between both locations is 0.
Mongo Doku $near
Query to find all nearest
Request.find({
address: {
location: {
$near: {
$geometry: {
type: 'Point' ,
coordinates: [8.4821159,49.4705199],
},
$maxDistance: 10000,
$minDistance: 0,
},
},
},
})
Mongoose Model
Edit (add): this.request.index({'address.location': '2dsphere'});
import mongoose from 'mongoose';
const ObjectId = mongoose.Schema.Types.ObjectId;
import {RequestMiddleware} from './RequestMiddleware';
class Request extends mongoose.Schema {
public request: mongoose.Schema;
constructor() {
const RequestSchema = {
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
category: {
type: ObjectId,
ref: 'Category',
required: true,
},
created_by: {
type: ObjectId,
ref: 'User',
required: true,
},
address: {
location: {
type: {
type: String,
enum: ['Point'],
default: 'Point',
required: true,
},
coordinates: {
type: [Number],
default: [0, 0],
required: true,
},
},
plz: {
type: String,
required: false,
},
city: {
type: String,
required: false,
},
street: {
type: String,
required: false,
},
street_nr: {
type: String,
required: false,
},
},
time_end: {
type: Date,
required: false,
},
confirmed_helper: {
type: ObjectId,
ref: 'User',
},
helper: [{
helperId: {
type: ObjectId,
ref: 'User',
},
offer_text: {
type: String,
},
}],
};
const request = super(RequestSchema, {
timestamps: {
createdAt: 'created_at',
updatedAt: 'updated_at',
},
});
this.request = request;
this.request.index({'address.location': '2dsphere'});
this.request.plugin(RequestMiddleware);
return this.request;
}
}
export default mongoose.model('Request', new Request());
Database:
You need two things:
2dspere index (probably you already have it):
db.col.createIndex( { "address.location" : "2dsphere" } )
and to modify your query so that it uses the dot notation instead of nested object:
let result = await Request.find({
'address.location': {
$near: {
$geometry: {
type: 'Point',
coordinates: [8.4821159, 49.4705199]
},
$maxDistance: 10000,
$minDistance: 0
}
}
});

mongooseJS return number of IDs in a collection

I'm using mongooseJS as a mongoDB driver in Javascript. I can return the number of fields in the database with the following code:
app.get('/total/', (req, res) => {
var id = req.params.id;
boxmac.count().then((macdb) => {
res.send({macdb});
}, (e) => {
res.status(404).send(e)
console.log(e);
});
});
Which when I load the file with node, and query the resulting link, I get
{
"macdb": 2108
}
However I'm trying to return the number of Unique ID's in the collection (should be 168-170). I've tried placing the id in various places (such as count({id}).then, but can't get the number of ID's.
here's my model:
var boxmac = mongoose.model('macdbs', {
ProductName: {
type: String,
required: true,
minlength: 1,
trim: true
},
OriginCountry: {
type: String,
default: false
},
StoreBrand: {
type: String,
default: null
},
Type: {
type: String,
default: null,
required: true
},
Pasta: {
type: String,
default: null,
required: false
},
ADC: {
type: String,
default: null,
required: false
},
PastaType: {
type: String,
default: null,
required: false
},
Org: {
type: String,
default: 'N',
required: false
},
Veg: {
type: String,
default: 'N',
required: false
},
Mic: {
type: String,
default: null,
required: false
},
Exp: {
type: String,
default: null,
required: false
},
PriceRaw: {
type: String,
default: null,
required: false
},
SauceType: {
type: String,
default: 'dry',
required: true
},
BoxSize: {
type: String,
default: null,
required: true
},
EpNo: {
type: Number,
default: null,
required: true
},
URL: {
type: String,
default: null,
required: true
},
Price: {
type: String,
default: null,
required: true
},
Rating: {
type: String,
default: null,
required: false
},
Comments: {
type: String,
default: null,
required: false
}
});

Categories