aggregate query taking long time. How we can improve performance - node.js

We are fetching data from applicant and ticket collection. applicant collection has 19000 records and ticket collection has 10000 records.
Please suggest how to improve the performance of the below query. Thanks in advance.
totalData = await applicantObj.aggregate([
{
$match: findApplicantCriteria
},
{
$lookup: {
from: 'tickets',
let: { applicant_id: '$_id' },
pipeline: [
{
$match: {
$expr:
findCriteria
}
}
],
as: 'tickets'
}
},
{
$project: {
_id: 0,
id: "$_id",
name: "$F_First_name",
phoneNumber: "$F_R_Mobile_no",
email: "$F_Email_id",
crn: "$Reg_No",
generatedTickets: { $size: "$tickets" },
}
},
{
$match: { generatedTickets: { "$gt": 0 } }
},
{
$count: "total"
}
])

Related

Mongoose - How to get unique data based on some fields using aggregation

I have these fields in the document,
doc: {
"id": "632ac8cba7723378033fef10",
"question": 1,
"text": "aasdfghjk,mnbvcxswertyuikmnbvcxsrtyuiknbvcdrtyujnbvcddtyjnbvfty",
"slug": "xcvbnrddfghjktdxjjydcvbyrsxcvbhytrsxggvbjkytrdgc",
"subject": 25866,
"tutorInfo": {
"tutorId": "632ac8cba7723378033fa0fe",
"tutorIncrementalId": 95947
}
}
the same tutorInfo can Occur in multiple documents.
const allQuestionBySubject = await QuestionParts.aggregate([
{
$match: {
$and: [
{
subject: subjectIncrementalId
},
{tutorInfo: {$exists: true}}
]
}
},
{ "$skip": page * limit },
{ "$limit": limit },
{
$lookup: {
from: "profiles",
localField: "tutorInfo.tutorIncrementalId",
foreignField: "incrementalId",
as: "tutorDetails"
}
}
])
Code to get a list of questions as per subject.
I am filtering documents based on subject and as I mentioned the same tutorInfo can be present in multiple documents so in the result same tutor can be present in multiple documents, How can I get a unique list of documents in which tutorInfo shouldn't be repeated.
Since the same tutorInfo is present in multiple records, You can use $group to group the document on the tutorInfo.tutorId field.
const allQuestionBySubject = await QuestionParts.aggregate(
[
{
$match: {
$and: [
{
subject: subjectIncrementalId
},
{ tutorInfo: { $exists: true } }
]
}
},
{ "$skip": page * limit },
{ "$limit": limit },
{
"$group": {
_id: "$tutorInfo.tutorId",
question: { $first: "$question" },
text: { $first: "$text" },
slug: { $first: "$slug" },
subject: { $first: "$orderId" },
tutorInfo: { $first: "$tutorInfo" },
}
},
{
$lookup: {
from: "profiles",
localField: "tutorInfo.tutorIncrementalId",
foreignField: "incrementalId",
as: "tutorDetails"
}
}
]
)

MongoDB: Aggregation not returning records after page 1

I am trying to get a return of data using aggregation and also I'm making pagination. I get results in page 1 but after page 2 there's only empty array. Can anyone help me? I'm not sure why I'm not getting any results after since I'm getting correct results in $match and $skip
user.aggregate([
{
$facet: {
"total": [
{ $match: { deletedAt: { $exists: false }},},
{ $count: "count" }
],
"users": [
{ $match: { deletedAt: { $exists: false }}},
{ $lookup: {
from: "userdetails",
localField: "_id",
foreignField: "user_id",
as: "details"
}},
{
$group: {
_id: "$_id",
username: { "$first": "$username" },
email: { "$first": "$email"},
accessCode: { "$first": "$accessCode"},
employer: { "$first": "$employer" },
domain: { "$first": "$domain" },
createdAt: { "$first": "$createdAt" },
updatedAt: { "$first": "$updatedAt" },
details: {
"$addToSet": "$details"
}
}
}
,{ $sort: sort },
{ $limit: items },
{ $skip: skip }
]
}
}
]).collation({ locale: "en"}).exec(function(err, users) {
var total;
var usersRecord;
if (!users) {
total = 0;
usersRecord =[];
} else {
total = users[0].total[0] ? users[0].total[0].count : 0;
usersRecord = users[0].users
}
let pages = total > 0 ? Math.ceil(total / items) : 1;
res.status(200).json(
{
'total': total,
'page': Number(page),
'pages': pages,
'items': usersRecord
})
})

How to calculate the percentage using facet in MongoDB?

I am calculating the notification percentage in my app for tracking some statistics.
My Collection:
[
{
_id: "123",
status: "seen",
userId: "589"
},
{
_id: "223",
status: "seen",
userId: "589"
},
{
_id: "474",
status: "unseen",
userId: "589"
},
{
_id: "875",
status: "seen",
userId: "112"
},
{
_id: "891",
status: "unseen",
userId: "112"
}
]
Expected Result:
Here we can see that, UserId - 589 has received 3 notifications out of which 2 are seen. So the calculation is (totalNumOfSeen/totalNumOfNoticationsSent) * 100
[{
userId: "589",
notificationPercentage : 66.66
},{
userId: "112",
notificationPercentage : 50
}]
I am using a facet for grouping and matching but that is returning me an array of object and I am not getting how to perform divide on this.
My Query:
db.collection.aggregate([
{
$facet: {
totalNumOfSeen: [
{
$match: {
userId: "589",
status: "seen"
}
},
{
$group: {
_id: "$userId",
totalNumOfSeen: {
$sum: 1
}
}
}
],
totalNumOfNoticationsSent: [
{
$match: {
userId: "589",
}
},
{
$group: {
_id: "$userId",
totalNumOfNoticationsSent: {
$sum: 1
}
}
}
]
}
}
])
The Above Query is giving me the below Result:
[
{
"totalNumOfNoticationsSent": [
{
"_id": "589",
"totalNumOfNoticationsSent": 3
}
],
"totalNumOfSeen": [
{
"_id": "589",
"totalNumOfSeen": 2
}
]
}
]
MongoPlayground - https://mongoplayground.net/p/jHn2ZlshgDL
Now I need to add one more field as notificationPercentage and calculate the notification percentage based on the above facet result. Really appreciate the help.
You can try,
$group by userId and get totalSeen count using $cond if status is seen, get total count of notification using $sum,
$project to show required fields, and calculate percentage using $divide and $multiply
db.collection.aggregate([
{
$group: {
_id: "$userId",
totalSeen: {
$sum: { $cond: [{ $eq: ["$status", "seen"] }, 1, 0] }
},
total: { $sum: 1 }
}
},
{
$project: {
_id: 0,
userId: "$_id",
notificationPercentage: {
$multiply: [{ $divide: ["$totalSeen", "$total"] }, 100]
}
}
}
])
Playground

Get the total amount of aggregated data in Mongoose

I have 2 documents: Locations and Orders
Let's say I have 4 locations, and some locations contain orders.
I'm already able to get a list of my locations with the corresponding orders for each location.
What I'm not able to do, is to include the amount of orders for each location, and the total expanses. (Each individual order already contain this information)
Here's Mongo Playground with my current code.
Notice that I want to populate "amount" and "total".
https://mongoplayground.net/p/FO_nYDOD1kn
This is what I use to aggregate my data:
db.Locations.aggregate([{
$lookup: {
from: "Orders",
let: {
loc_id: "$_id"
},
pipeline: [{
$match: {
$expr: {
$eq: ["$$loc_id", "$location"]
}
}
}, {
$project: {
_id: 0,
products: 1
}
}],
as: "orders"
}
}, {
$project: {
_id: 1,
name: 1,
orders: {
total: "insert total orders expanses in this order",
amount: "insert amount of orders for this location",
orders: "$orders"
}
}
}])
and the structure of a single order:
{
"_id": "5e17ab585eb7f11a971bce5c",
"location": "5e17a001f1e0220def7a2b5d",
"total": "1000"
}
Alright, I made something work! Yay!
Here's the solution for whoever finds this.
Location
.aggregate([
{
$lookup: {
from: "orders",
let: { loc_id: "$_id" },
pipeline: [{ $match: { $expr: { $eq: ["$$loc_id", "$location"] } } }],
as: "order"
}
}
,
{
$project: {
_id: 1,
name: 1,
address: 1,
orders: {
total: { $sum: "$order.total" },
amount: { $size: "$order" },
items: "$order"
}
}
}
])
.then(locations => {
res.status(200).json({
success: true,
locations
})
})
.catch(error => {
res.status(500).json({
success: false,
error
})
})

how to fetch seller order from multiple collection data

I have 4 collections for store order data.
1. order => field => _id, order_no, cust_id, order_date
2. order_address => field => _id, order_id, cust_name, mobile, address
3. order_details => field => _id, order_id, product_id, seller_id, qty, price
4. order_payment => field => _id, payment_type, payment_status
in that order_details collection has n number of record for a number of product in one order.
in that how to get particular seller order from my data using aggregate in node.js from MongoDB database
i try this code but it's show ordre_details = [] but show order in my result:
var query = [
{ "$lookup": {
from: 'order_details',
let: { order_id: "$_id" },
pipeline: [
{ $match: { $expr: { $and: [{ $eq: [ "$order_id", "$$order_id" ] }, { $eq: [ "$seller_id", ObjectID(seller_id) ] }] } } },
{ $project: {
amount: 1,
cod_charge: 1,
shipping_charge: 1,
pid: 1,
product_attribute_id: 1,
qty: 1
} },
{ "$lookup": {
from: 'product',
let: { product_id: "$pid", product_attribute_id: '$product_attribute_id'},
pipeline: [
{ $match: { $expr: { $eq: [ "$_id", "$$product_id" ] } } },
{ $project: { _id: 1, name: 1, sku: 1 } },
{ "$lookup": {
from: 'product_image',
let: { product_attribute_id: '$$product_attribute_id' },
pipeline: [
{ $match: { $expr: { $eq: [ "$product_attribute_id", "$$product_attribute_id" ] } } },
{ $project: { _id: 0, image: 1, is_default: 1 } },
{ $sort : { is_default: -1 } },
{ $replaceRoot: { newRoot: {_id: "$_id", image: "$image" } } }
],
as: 'product_image'
} },
{ $replaceRoot: { newRoot: {
_id: "$_id",
name: "$name",
sku: "$sku",
image: { $arrayElemAt: [ "$product_image.image", 0 ] }
} } }
],
as: 'product'
} },
{ "$replaceRoot": { newRoot: {
_id: '$$ROOT._id',
pid: '$$ROOT.pid',
amount: '$$ROOT.amount',
cod_charge: '$$ROOT.cod_charge',
shipping_charge: '$$ROOT.shipping_charge',
product_attribute_id: "$$ROOT.product_attribute_id",
qty: "$$ROOT.qty",
product: { $arrayElemAt: [ "$product", 0 ] },
} } },
],
as: 'order_details'
} },
{ "$replaceRoot": {
newRoot: {
_id: "$_id",
order_no: "$order_no",
cust_id: "$cust_id",
order_date: "$order_date",
order_details: "$order_details"
}
} }
]
orderModel.order.aggregate(query, function(err, orderData){})

Resources