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
})
})
Related
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"
}
}
]
)
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"
}
])
I have two collections Projects and Users.
Projects has a budget field with the following: 1)amount and 2)currency
{
_id: ObjectId(...),
type: 'typeA',
budget: {
amount: 123,
currency: 'USD'
}
}
Users has a field called bids which contains list of objects with fields amount and currency.
{
_id: ObjectId(...),
name: "User name",
bids: [{amount: 123, currency: "USD"}, {amount: 342, currency: "INR"}]
}
I am trying to join Users with Projects using a lookup aggregation.
db.Projects.aggregate([
{
$lookup: {
from: "Users",
let: { projectAmount: "$budget.amount", projectCurrency: "$budget.currency" },
pipeline: [
{$match: {
$expr: {
$and: [
{ $eq: ["$bids.amount", "$$projectAmount"] },
{ $eq: ["$bids.currency", "$$projectCurrency"] }
]
}
}}
],
as: "matchingBids"
}
]);
But I am always getting the empty result though I have some matching objects in the Users collection. I've gone through the official docs and internet but didn't find anything helpful. Any help would be appreciated. Thank you
Try $in operator with full object and array
pass budget object in let
check $in condition with bids array
db.Projects.aggregate([
{
$lookup: {
from: "Users",
let: { budget: "$budget" },
pipeline: [
{
$match: {
$expr: { $in: ["$$budget", "$bids"] }
}
}
],
as: "matchingBids"
}
}
])
Playground
WARNING:
The above approach will work only when order of fields in object and array of object should be same, below examples will not work!
budget: { amount: 123, currency: "USD" }
bids: [{ currency: "USD", amount: 123 }]
OR
budget: { currency: "USD", amount: 123 }
bids: [{ amount: 123, currency: "USD" }]
EDIT:
After some workaround i found a way to make sure to match exact fields to overcome above situation,
$or condition with both possibility of fields position {amount, currency} and {currency, amount}
db.Projects.aggregate([
{
$lookup: {
from: "Users",
let: { budget: "$budget" },
pipeline: [
{
$match: {
$expr: {
$or: [
{
$in: [
{ amount: "$$budget.amount", currency: "$$budget.currency" },
"$bids"
]
},
{
$in: [
{ currency: "$$budget.currency", amount: "$$budget.amount" },
"$bids"
]
}
]
}
}
}
],
as: "matchingBids"
}
}
])
Playground
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
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){})