Reputation: 21
I want only that data in "present" which is matched with student _id. But for now by this query I'm getting all student counts in every individual students data.
Student Schema
const StudentSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, "Please Provide Name"],
maxlength: 100,
minlength: 2,
},
email: {
type: String,
required: [true, "Please Provide Email"],
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,}))$/,
"Please Provide a Valid Email",
],
unique: true,
},
number: {
type: String,
required: [true, "Please Provide Number"],
match: [
/^(?:(?:\+|0{0,2})91(\s*[\-]\s*)?|[0]?)?[789]\d{9}$/,
"Please Provide a Valid Number",
],
unique: true,
},
rollNumber: {
type: Number,
required: [true, "Please Provide Roll Number"],
maxlength: 5,
},
departmentID: {
type: mongoose.Types.ObjectId,
ref: "Department",
required: [true, "Please Provide departmentID"],
},
classID: {
type: mongoose.Types.ObjectId,
ref: "Class",
required: [true, "Please Provide classID"],
},
position: {
type: String,
required: [true, "Please Provide Position"],
enum: ["Student"],
default: "Student",
},
password: {
type: String,
required: [true, "Please Provide Password"],
minlength: 6,
},
},
{ timestamps: true }
);
Attendance Schema
const mongoose = require("mongoose");
const { Schema } = mongoose;
const AttendanceSchema = new Schema(
{
date: {
type: String,
required: [true, "Please Provide Date"],
maxlength: 15,
minlength: 5,
},
subjectID: {
type: mongoose.Types.ObjectId,
ref: "Subject",
required: [true, "Please Provide Subject"],
},
studentID: [
{
type: mongoose.Types.ObjectId,
ref: "Student",
required: [true, "Please Provide Student"],
},
],
teacherID: {
type: mongoose.Types.ObjectId,
ref: "Faculty",
required: [true, "Please Provide Teacher"],
},
classID: {
type: mongoose.Types.ObjectId,
ref: "Class",
required: [true, "Please Provide Class"],
},
departmentID: {
type: mongoose.Types.ObjectId,
ref: "Department",
required: [true, "Please Provide Department"],
},
},
{ timestamps: true }
);
module.exports = mongoose.model("Attendance", AttendanceSchema);
The Query I'm Writing
await StudentSchema.aggregate([
{
$match: {
classID: mongoose.Types.ObjectId(`${req.params.id}`),
},
},
{
$project: { createdAt: 0, updatedAt: 0, __v: 0, password: 0 },
},
{
$lookup: {
from: "attendances",
pipeline: [
{
$match: {
subjectID: mongoose.Types.ObjectId(`${req.params.Sid}`),
},
},
{ $unwind: "$studentID" },
{ $group: { _id: "$studentID", count: { $sum: 1 } } },
],
as: "present",
},
},
Data I'm Getting From This Query
{
"subject1": [
{
"_id": "635d40803352895afffdc294",
"name": "D R",
"email": "[email protected]",
"number": "9198998888",
"rollNumber": 202,
"departmentID": "635a8ca21444a47d65d32c1a",
"classID": "635a92141a081229013255b4",
"position": "Student",
"present": [
{
"_id": "635d40803352895afffdc294",
"count": 3
},
{
"_id": "635eb8898dea5f437789b751",
"count": 2
}
]
},
{
"_id": "635eb8898dea5f437789b751",
"name": "V R",
"email": "[email protected]",
"number": "9198998899",
"rollNumber": 203,
"departmentID": "635a8ca21444a47d65d32c1a",
"classID": "635a92141a081229013255b4",
"position": "Student",
"present": [
{
"_id": "635d40803352895afffdc294",
"count": 3
},
{
"_id": "635eb8898dea5f437789b751",
"count": 2
}
]
}
]
}
This type of data I'm trying to achieve. Only that data which will be matched with _id in present array.
{
"subject1": [
{
"_id": "635d40803352895afffdc294",
"name": "D R",
"email": "[email protected]",
"number": "9198998888",
"rollNumber": 202,
"departmentID": "635a8ca21444a47d65d32c1a",
"classID": "635a92141a081229013255b4",
"position": "Student",
"present": [
{
"_id": "635d40803352895afffdc294",
"count": 3
}
]
},
{
"_id": "635eb8898dea5f437789b751",
"name": "V R",
"email": "[email protected]",
"number": "9198998899",
"rollNumber": 203,
"departmentID": "635a8ca21444a47d65d32c1a",
"classID": "635a92141a081229013255b4",
"position": "Student",
"present": [
{
"_id": "635eb8898dea5f437789b751",
"count": 2
}
]
}
]
}
Upvotes: 1
Views: 34
Reputation: 22296
You can just use the let
option in the $lookup
and pass the studentId
, then you could match the proper attendances as part of the $lookup
stage, like so:
{
$lookup: {
from: "attendances",
let: {
studentID: "$_id"
},
pipeline: [
{
$match: {
subjectID: 2,
$expr: {
$eq: [
"$$studentID",
"$studentID"
]
}
}
},
{
$unwind: "$studentID"
},
{
$group: {
_id: "$studentID",
count: {
$sum: 1
}
}
}
],
as: "present"
}
}
Another alternative would be to filter out the present
array at the end but that would be less efficient and will uglify the code.
Upvotes: 1