How to use `$unwind` to iterate exact value - mongodb

I am new to mongoose and mongodb.
In my addtocart schema I have added $lookups and projection to populate products in add to cart.
In current response product_purchase_quantity it was in array in add to cart collection it is key and value. So, in $lookups I tried to add {$unwind: '$product_purchase_quantity'} but after adding add_to_cart_products object prints twice. I don't know where the mistake was?
Below i have mentioned expected result.
AddToCart Schema:
lookups: [
{
from: 'shop_db_products',
let: {
productId: '$add_to_cart_products.product',
purchaseQuantity: '$add_to_cart_products.product_quantity',
productItemId: '$add_to_cart_products.product_item',
},
pipeline: [
{
$match: { $expr: { $in: ['$_id', '$$productId'] } },
},
{
$lookup: {
from: 'shop_db_products',
localField: 'product_id',
foreignField: '_id',
as: 'products',
},
},
{
$project: {
_id: true,
product: {
_id: '$_id',
product_name: '$product_name',
},
product_purchase_quantity: '$$purchaseQuantity',
product_item: {
$reduce: {
input: {
$filter: {
input: '$product_items',
cond: {
$in: ['$$this._id', '$$productItemId'],
},
},
},
initialValue: {},
in: {
_id: '$$this._id',
product_size: { $concat: [{ $toString: '$$this.product_size.value' }, '$$this.product_size.unit'] },
product_price: '$$this.product_price',
product_type: '$$this.product_type'
},
},
},
},
},
],
localField: '',
as: 'add_to_cart_products',
model: 'ProductModel',
},
],
AddToCart Collection
[
{
"add_to_cart_user": "5f0076b7bd530928fc0c0285",
"add_to_cart_products": [
{
"product": "5f05a0270b4f3a5c41c70826",
"product_item": "5f05a0270b4f3a5c41c70877",
"product_quantity": 5
},
{
"product": "5f05a0270b4f3a5c41c70827",
"product_item": "5f05a0270b4f3a5c41c70666",
"product_quantity": 3
}
],
"add_to_cart_product_total": 5,
"add_to_cart_discount": 50,
"add_to_tax": "5eae321d21924800122f978e",
"add_to_cart_grand_total": 500
}
]
Current Response:
{
"_id": "5fa2a09b3c6316482098f6ff",
"add_to_cart_status_is_active": true,
"add_to_cart_discount": 50,
"add_to_cart_tax": 8,
"add_to_cart_products": [
{
"product": {
"_id": "5f05a0270b4f3a5c41c70826",
"product_name": "Avery Apricot Sour"
},
"product_purchase_quantity": [
5,
3
],
"product_item": {
"_id": "5f05a0270b4f3a5c41c70877",
"product_size": "22oz",
"product_price": 13.99
}
},
{
"product": {
"_id": "5f05a0270b4f3a5c41c70827",
"product_name": "Avery Dugana"
},
"product_purchase_quantity": [
5,
3
],
"product_item": {
"_id": "5f05a0270b4f3a5c41c70666",
"product_size": "22oz",
"product_price": 8.99
}
}
]
}
Expected response:
{
"_id": "5fa2a09b3c6316482098f6ff",
"add_to_cart_status_is_active": true,
"add_to_cart_discount": 50,
"add_to_cart_tax": 8,
"add_to_cart_products": [
{
"product": {
"_id": "5f05a0270b4f3a5c41c70826",
"product_name": "Avery Apricot Sour"
},
"product_purchase_quantity": 5,
"product_item": {
"_id": "5f05a0270b4f3a5c41c70877",
"product_size": "22oz",
"product_price": 13.99
}
},
{
"product": {
"_id": "5f05a0270b4f3a5c41c70827",
"product_name": "Avery Dugana"
},
"product_purchase_quantity": 3,
"product_item": {
"_id": "5f05a0270b4f3a5c41c70666",
"product_size": "22oz",
"product_price": 8.99
}
}
]
}
Product (shop_db_products) collection:
[
{
"_id": "5f05a0270b4f3a5c41c70826",
"product_no": "PRO04087",
"product_store_no": "1001",
"product_dept_no": "Irish Whiskey",
"product_name": "2Gingers",
"product_overview": "No Overview",
"product_items": [
{
"_id": "5f05a0270b4f3a5c41c70877",
"product_item_number": "857566003019",
"product_price": 20.99,
"product_cost": 20.99,
"product_size": "750ml",
"product_type": "Bottle",
"product_value": 0,
"product_quantity": 0,
"product_images": [
"pro04087-857566003019-1.png"
],
"product_item_is_active": true
}
]
},
...
]

You have to $unwind add_to_cart_products before performing $lookup
db.addToCart.aggregate([
{
$unwind: "$add_to_cart_products"
},
{
$lookup: {
from: "shop_db_products",
let: {
productId: "$add_to_cart_products.product",
purchaseQuantity: "$add_to_cart_products.product_quantity",
productItemId: "$add_to_cart_products.product_item"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$_id",
"$$productId"
]
}
}
},
{
$project: {
_id: true,
product: {
_id: "$_id",
product_name: "$product_name",
},
product_purchase_quantity: "$$purchaseQuantity",
product_item: {
$reduce: {
input: {
$filter: {
input: "$product_items",
cond: {
$eq: [
"$$this._id",
"$$productItemId"
],
},
},
},
initialValue: {},
in: {
_id: "$$this._id",
product_size: "$$this.product_size",
product_price: "$$this.product_price",
product_type: "$$this.product_type"
}
}
}
}
}
],
as: "add_to_cart_products"
}
},
{
$unwind: "$add_to_cart_products"
},
{
$group: {
_id: "$_id",
"add_to_cart_products": {
$push: "$add_to_cart_products"
}
}
}
])
MongoDB Playground

Another way
Without reducer, with $unwind
https://mongoplayground.net/p/3uWA5pVBv83
db.addToCart.aggregate([
{
"$unwind": "$add_to_cart_products"
},
{
"$lookup": {
"from": "shop_db_products",
"let": {
"productId": "$add_to_cart_products.product",
"purchaseQuantity": "$add_to_cart_products.product_quantity",
"productItemId": "$add_to_cart_products.product_item"
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$_id",
"$$productId"
]
}
}
},
{
"$unwind": "$product_items"
},
{
"$match": {
"$expr": {
"$eq": [
"$product_items._id",
"$$productItemId"
]
}
}
},
{
"$project": {
"_id": true,
"product": {
"_id": "$_id",
"product_name": "$product_name"
},
"product_purchase_quantity": "$$purchaseQuantity",
"product_item": "$product_items"
}
}
],
"as": "productResolved"
}
},
{
"$unwind": "$productResolved"
},
{
"$group": {
"_id": "$_id",
"add_to_cart_products": {
"$push": "$productResolved"
}
}
}
])

Related

Mongodb Aggregation :- Get specific fields from $lookup nested array

I am trying to get specific fields from the array I got after aggregate, lookup and some cond
Below you can see my query
const attendanceData = await User.aggregate([
{
$match: {
lastLocationId: Mongoose.Types.ObjectId(typeId),
isActive: true,
},
},
{
$project: {
_id: 1,
workerId: 1,
workerFirstName: 1,
workerSurname: 1,
},
},
{
$lookup: {
from: "attendances",
localField: "_id",
foreignField: "employeeId",
as: "attendances",
},
},
{
$set: {
attendances: {
$filter: {
input: "$attendances",
cond: {
$and: [
{
$gte: ["$$this.Date", new Date(fromDate)],
},
{
$lte: ["$$this.Date", new Date(toDate)],
},
{
$eq: ["$$this.createdAs", dataType],
},
{
$eq: ["$$this.status", true],
},
{
$eq: ["$$this.workerType", workerType],
},
],
},
},
},
},
},
{ $skip: 0 },
{ $limit: 10 },
]);
The data as a response i get below
{
"attendanceSheet": [
{
"_id": "60dd77c14524e6c116e16aaa",
"workerFirstName": "FIRST NAME1",
"workerSurname": "SURNAME1",
"workerId": "1",
"attendances": [
{
"_id": "6130781085b5055a15c32f2u",
"workerId": "1",
"workerFullName": "FIRST NAME",
"workerType": "Employee",
"Date": "2022-10-01T00:00:00.000Z",
"createdAs": "ABSENT"
},
{
"_id": "6130781085b5055a15c32f2u",
"workerId": "1",
"workerFullName": "FIRST NAME",
"workerType": "Employee",
"Date": "2022-10-02T00:00:00.000Z",
"createdAs": "ABSENT"
}
]
},
{
"_id": "60dd77c24524e6c116e16c0f",
"workerFirstName": "FIRST NAME2",
"workerSurname": "Surname",
"workerId": "2",
"attendances": [
{
"_id": "6130781a85b5055a15c3455y",
"workerId": "2",
"workerFullName": "FIRST NAME2",
"workerType": "Employee",
"Date": "2022-10-02T00:00:00.000Z",
"createdAs": "ABSENT"
}
]
}
]
}
But I want data something like this below only few fields in not every fields
{
"attendanceSheet": [
{
"_id": "60dd77c14524e6c116e16aaa",
"workerFirstName": "FIRST NAME1",
"workerSurname": "Surname",
"workerId": "1",
"attendances": [
{
"_id": "6130781085b5055a15c32f2u",
"Date": "2022-10-01T00:00:00.000Z",
"createdAs": "ABSENT"
},
{
"_id": "6130781085b5055a15c32f2u",
"Date": "2022-10-02T00:00:00.000Z",
"createdAs": "ABSENT"
}
]
},
{
"_id": "60dd77c24524e6c116e16c0f",
"workerFirstName": "FIRST NAME2",
"workerSurname": "Surname",
"workerId": "2",
"attendances": [
{
"_id": "6130781a85b5055a15c3455y",
"Date": "2022-10-02T00:00:00.000Z",
"createdAs": "ABSENT"
}
]
}
]
}
You could simplify/refactor your aggregation pipeline by putting all the matching in a "$lookup" "pipeline".
db.users.aggregate([
{
"$match": {
"lastLocationId": ObjectId("0123456789abcdef01234567"),
"isActive": true
}
},
{
"$project": {
"workerId": 1,
"workerFirstName": 1,
"workerSurname": 1
}
},
{
"$lookup": {
"from": "attendances",
"localField": "_id",
"foreignField": "employeeId",
"as": "attendances",
// do all the matching here
"pipeline": [
{
"$match": {
"Date": {
// fromDate, toDate
"$gte": ISODate("2022-09-01T00:00:00Z"),
"$lte": ISODate("2022-09-30T23:59:59Z")
},
// dataType
"createdAs": "ABSENT",
"status": true,
// workerType
"workerType": "Employee"
}
},
{
"$project": {
"Date": 1,
"createdAs": 1
}
}
]
}
},
{$skip: 0},
{$limit: 10}
])
Try it on mongoplayground.net.
One option to get from what you have to the requested output is to $map and $reduce:
db.collection.aggregate([
{
$set: {
attendanceSheet: {
$map: {
input: "$attendanceSheet",
as: "external",
in: {
$mergeObjects: [
"$$external",
{
attendances: {
$reduce: {
input: "$$external.attendances",
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
{
_id: "$$this._id",
createdAs: "$$this.createdAs",
Date: "$$this.Date"
}
]
]
}
}
}
}
]
}
}
}
}
}
])
See how it works on the playground example
The below modification worked for me
const attendanceData = await User.aggregate([
{
$match: {
lastLocationId: Mongoose.Types.ObjectId(typeId),
isActive: true,
},
},
{
$project: {
_id: 1,
workerId: 1,
workerFirstName: 1,
workerSurname: 1,
},
},
{
$lookup: {
from: "attendances",
localField: "_id",
foreignField: "employeeId",
as: "attendances",
},
},
{
$set: {
attendances: {
$filter: {
input: "$attendances",
cond: {
$and: [
{
$gte: ["$$this.Date", new Date(fromDate)],
},
{
$lte: ["$$this.Date", new Date(toDate)],
},
{
$eq: ["$$this.createdAs", dataType],
},
{
$eq: ["$$this.status", true],
},
{
$eq: ["$$this.workerType", workerType],
},
],
},
},
},
},
},
{
$set: {
attendances: {
$reduce: {
input: "$attendances",
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
{
_id: "$$this._id",
createdAs: "$$this.createdAs",
Date: "$$this.Date",
},
],
],
},
},
},
},
},
{ $skip: 0 },
{ $limit: 10 },
]);

Mongodb Aggregate Filter Array Of Array Of Array

We would like to filter SKU's List which has verificationData data and differenceInStock difference greater than or Less than 0
Here is an example Data Set.
[
{
"_id": "636e0beaa13ef73324e613f0",
"status": "ACTIVE",
"inventory": 132,
"parentCategory": [
"Salt"
],
"title": "Aashirvaad MRP: 28Rs Salt 27 kg Bopp Bag (Set of 1 kg x 27)",
"createdAt": "2022-11-11T08:46:34.950Z",
"updatedAt": "2022-11-24T17:43:27.361Z",
"__v": 3,
"verificationData": [
{
"_id": "637c57ebbe783a9a138fc2d3",
"verificationDate": "2022-11-22T05:02:35.155Z",
"items": {
"listingId": "636e0beaa13ef73324e613f0",
"phyiscalVerification": [
{
"verifiedBy": "634534e72ef6462fcb681a39",
"closingStock": 178,
"phyiscalStock": 178,
"differenceInStock": 0,
"verifiedAt": "2022-11-22T10:19:38.388Z",
"_id": "637ca23abe783a9a1394f402"
}
],
"_id": "637ca23abe783a9a1394f401"
},
"yearMonthDayUTC": "2022-11-22"
},
{
"_id": "637d9b65be783a9a13998726",
"verificationDate": "2022-11-23T04:02:45.804Z",
"items": {
"listingId": "636e0beaa13ef73324e613f0",
"phyiscalVerification": [
{
"verifiedBy": "634534e72ef6462fcb681a39",
"closingStock": 161,
"phyiscalStock": 167,
"differenceInStock": 6,
"verifiedAt": "2022-11-23T09:52:36.815Z",
"_id": "637ded64be783a9a13a29d55"
}
],
"_id": "637ded64be783a9a13a29d54"
},
"yearMonthDayUTC": "2022-11-23"
},
{
"_id": "637f0254be783a9a13a94354",
"verificationDate": "2022-11-24T05:34:12.995Z",
"items": {
"listingId": "636e0beaa13ef73324e613f0",
"phyiscalVerification": [
{
"verifiedBy": "634534e72ef6462fcb681a39",
"closingStock": 144,
"phyiscalStock": 146,
"differenceInStock": 2,
"verifiedAt": "2022-11-24T12:02:28.123Z",
"_id": "637f5d54be783a9a13b1039a"
}
],
"_id": "637f5d54be783a9a13b10399"
},
"yearMonthDayUTC": "2022-11-24"
},
{
"_id": "2022-11-25",
"yearMonthDayUTC": "2022-11-25",
"items": null
}
]
},
{
"_id": "62b5c39062ddb963fc64c42d",
"status": "ACTIVE",
"inventory": 10,
"parentCategory": [
"Salt"
],
"finalMeasurementUnit": "kg",
"finalMeasure": "1 kg",
"title": "Marvella Citric Acid Lemon Salt 1 kg Pouch (Set of 500 gm x 2)",
"createdAt": "2022-06-24T14:00:49.052Z",
"updatedAt": "2022-11-21T11:04:21.643Z",
"__v": 2,
"verificationData": [
{
"_id": "2022-11-22",
"yearMonthDayUTC": "2022-11-22",
"items": null
},
{
"_id": "2022-11-23",
"yearMonthDayUTC": "2022-11-23",
"items": null
},
{
"_id": "2022-11-24",
"yearMonthDayUTC": "2022-11-24",
"items": null
},
{
"_id": "2022-11-25",
"yearMonthDayUTC": "2022-11-25",
"items": null
}
]
}
]
This could have array of 100+ SKU's
Our Aggregate Functions is as Follows
let reqData = await userListing.aggregate([
{
$match: {
warehouseId: { $eq: ObjectId(warehouseId) },
parentCategory: { $in: catList },
isWarehouseListing: { $eq: true },
isBlocked: { $ne: true },
isArchived: { $ne: true },
},
},
{ $sort: { whAddedAt: -1 } },
{
$lookup: {
from: "listingstockverifications",
let: { listId: "$_id" },
pipeline: [
{
$match: {
verificationDate: {
$gte: newFromDate,
$lt: newToDate,
},
},
},
{
$project: {
verificationDate: 1,
items: {
$filter: {
input: "$items",
cond: {
$and: [
/* {
"$$this.phyiscalVerification": {
$filter: {
input: "$$this.phyiscalVerification",
as: "psitem",
cond: { $gt: [ "$$psitem.differenceInStock", 0 ] },
},
},
}, */
{
$eq: ["$$this.listingId", "$$listId"],
},
],
},
},
},
yearMonthDayUTC: {
$dateToString: {
format: "%Y-%m-%d",
date: "$verificationDate",
},
},
},
},
{ $unwind: "$items" },
],
as: "stockVerification",
},
},
{
$addFields: {
verificationData: {
$map: {
input: dummyArray,
as: "date",
in: {
$let: {
vars: {
dateIndex: {
$indexOfArray: [
"$stockVerification.yearMonthDayUTC",
"$$date",
],
},
},
in: {
$cond: {
if: { $ne: ["$$dateIndex", -1] },
then: {
$arrayElemAt: ["$stockVerification", "$$dateIndex"],
},
else: {
_id: "$$date",
yearMonthDayUTC: "$$date",
items: null,
},
},
},
},
},
},
},
},
},
{
$project: {
stockVerification: 0,
},
},
]);
At Last now we would like to filter the SKU List the which has following Data
verificationData[].items.phyiscalVerification[].differenceInStock is Greater than or Less than 0
Expected Output in the following Exmaple would be 1st SKUs
as 2nd SKU does not have any Item Data
and even if in 3rd SKU if we got Item Data but should match the following condition
verificationData[].items.phyiscalVerification[].differenceInStock is Greater than or Less than 0
Thank you for taking your time to read and support.
You can add these two following stages to your aggregation, The idea is simple - just filter out all subdocuments that do not match the condition.
Because of the nested structure it's just not the sexiest of pipelines but it will suffice.
db.collection.aggregate([
{
$match: {
$or: [
{
"verificationData.items.phyiscalVerification.differenceInStock": {
$gt: 0
}
},
{
"verificationData.items.phyiscalVerification.differenceInStock": {
$lt: 0
}
}
]
}
},
{
$addFields: {
verificationData: {
$filter: {
input: {
$map: {
input: {
$filter: {
input: "$verificationData",
as: "verification",
cond: {
$ne: [
"$$verification.items",
null
]
}
}
},
as: "top",
in: {
$mergeObjects: [
"$$top",
{
"items": {
"$mergeObjects": [
"$$top.items",
{
phyiscalVerification: {
$filter: {
input: "$$top.items.phyiscalVerification",
as: "pshycical",
cond: {
$ne: [
"$$pshycical.differenceInStock",
0
]
}
}
}
}
]
}
}
]
}
}
},
cond: {
$gt: [
{
$size: "$$this.items.phyiscalVerification"
},
0
]
}
}
}
}
}
])
Mongo Playground

How to combine two aggregate function result in MongoDB

I have these two aggregations, as shown below.
The first one returns the clients that have zero visits(no visit objects created for the client).
The second one returns the clients with less visits than the others(at least 5).
I want to combine these two aggregations results into one so that they will be ordered like this:
[ no visits clients,
least visits clients ]
Is that possible without simply using Array concat method?
these two aggregations:
let clients = await clientModel.aggregate([
{
$lookup: {
from: "visits",
localField: "_id",
foreignField: "client",
as: "visits",
},
},
{
$project: {
_id: 1,
name: 1,
count: {
$size: "$visits",
},
},
},
{
$match: {
count: 0,
},
},
{
$project: {
_id: 1,
name: 1,
},
},
]);
with this result :
"Zero visits": [
{
"_id": "6182ebe5ea218257521cdc36",
"name": "cleint_807"
},
{
"_id": "6182ebfaea218257521cdc9a",
"name": "cleint_907"
},
{
"_id": "6182ec02ea218257521cdcbe",
"name": "cleint_943"
},
{
"_id": "6182ec20ea218257521cdd48",
"name": "cleint_71"
},
{
"_id": "6182ec29ea218257521cdd74",
"name": "cleint_115"
},
{
"_id": "6182ec54ea218257521cde5a",
"name": "cleint_345"
},
{
"_id": "6182ec61ea218257521cdea3",
"name": "cleint_418"
},
{
"_id": "6182ec71ea218257521cdef4",
"name": "cleint_499"
},
{
"_id": "6182ec96ea218257521cdfbc",
"name": "cleint_699"
}
],
Second aggregation:
visits = await visitModel.aggregate([
{ $match: { time: { $lte: +to, $gte: +from } } },
{
$project: {
date: {
$toDate: "$time",
},
client: 1,
},
},
{
$project: {
day: {
$dayOfWeek: "$date",
},
client: 1,
},
},
{
$match: {
day: 2,
},
},
{
$group: {
_id: {
client: "$client",
},
count: {
$sum: 1,
},
},
},
{
$sort: {
count: 1,
},
},
{
$limit: 10,
},
{
$lookup: {
from: "clients",
localField: "_id.client",
foreignField: "_id",
as: "client",
},
},
{
$unwind: {
path: "$client",
preserveNullAndEmptyArrays: false,
},
},
{
$project: {
_id: "$client._id",
name: "$client.name",
},
},
]);
with this result :
"Less visits": [
{
"_id": "6182eb73ea218257521cd9f6",
"name": "cleint_231"
},
{
"_id": "6182ebe9ea218257521cdc48",
"name": "cleint_825"
},
{
"_id": "6182ec7dea218257521cdf35",
"name": "cleint_564"
},
{
"_id": "6182ec2cea218257521cdd83",
"name": "cleint_130"
},
{
"_id": "6182ebd6ea218257521cdbe8",
"name": "cleint_729"
},
{
"_id": "6182ebc6ea218257521cdb9c",
"name": "cleint_653"
},
{
"_id": "6182ec0bea218257521cdced",
"name": "cleint_990"
},
{
"_id": "6182ebd3ea218257521cdbd8",
"name": "cleint_713"
},
{
"_id": "6182ec81ea218257521cdf48",
"name": "cleint_583"
},
{
"_id": "6182ec2cea218257521cdd85",
"name": "cleint_132"
}
]
Response
res.json({
success: true,
"Zero visits": clients,
"Less visits": visits,
});
};
I need to combine both results
Use $unionWith:
clientModel.aggregate([
<stage1>, ...
{ $unionWith: { coll: "visits", pipeline: [ <stage1>, ... ] } }
])

MongoDB Count With Condition within Project with $eq

I'm trying to count my "$attendance.status" with aggregation mongodb.
I've get my data with relations. then i want to count by relation columns like 'present', 'off', etc.
code
Employee.aggregate([
{
$lookup: {
from: "Attendance",
let: { employeeId: "$_id" },
pipeline: [
{
$match: {
$and: [
{ $expr: { $eq: ["$employeeId", "$$employeeId"] } },
{ isApproved: true },
{
createdAt: {
$gte: startOfMonth.toDate(),
$lte: endOfMonth.toDate(),
},
},
],
},
},
],
as: "attendance",
},
},
{
$project: {
_id: 1,
username: 1,
name: 1,
attendance: 1,
present: { $sum: { $eq: ["$attendance.status", "present"] } },
},
},
]);
But why cannot count my column?
i use $eq, with $sum then count the result. but the result is 0
{
"username": "Ethyl",
"name": "Kuhn",
"id": "614d43cde735f3e601dea165",
"attendance": [
{
"_id": "614d43cde735f3e601dea16f",
"status": "present",
"start": "2021-09-24T03:19:41.645Z",
"employeeId": "614d43cde735f3e601dea165",
"isApproved": true
},
],
"present": 0,
"sick": 0,
"off": 0,
},

How to Populate data using Mongodb Aggregate framework?

I have a current MongoDB Aggregate framework pipeline from a previous question and I am unable to add populate query to grab user profile by id.
My code is below
Product.aggregate([
{
$group: {
_id: {
hub: "$hub",
status: "$productStatus",
},
count: { $sum: 1 },
},
},
{
$group: {
_id: "$_id.hub",
counts: {
$push: {
k: "$_id.status",
v: "$count",
},
},
},
},
{
$group: {
_id: null,
counts: {
$push: {
k: { $toString: "$_id" },
v: "$counts",
},
},
},
},
{
$addFields: {
counts: {
$map: {
input: "$counts",
in: {
$mergeObjects: [
"$$this",
{ v: { $arrayToObject: "$$this.v" } },
],
},
},
},
},
},
{
$replaceRoot: {
newRoot: { $arrayToObject: "$counts" },
},
},
]);
and got the following result
[
{
"5fe75679e6f7a62ddaf5b2e9": {
"in progress": 5,
"Cancelled": 4,
"return": 1,
"on the way": 3,
"pending": 13,
"Delivered": 4
}
}
]
Expected Output
I need to grab user information from user collections using the hubId "5fe75679e6f7a62ddaf5b2e9" and expect a final result of the form below
[
{
"hub": {
"photo": "avatar.jpg",
"_id": "5fe75679e6f7a62ddaf5b2e9",
"name": "Dhaka Branch",
"phone": "34534543"
},
"statusCounts": {
"in progress": 5,
"Cancelled": 4,
"return": 1,
"on the way": 3,
"pending": 13,
"Delivered": 4
}
}
]
First id is user id and available in user collections.
You need to tweak your aggregate pipeline a little bit and include new pipeline stage like $lookup that populates the
hub
Product.aggregate([
{ "$group": {
"_id": {
"hubId": "$hubId",
"status": "$productStatus"
},
"count": { "$sum": 1 }
} },
{ "$group": {
"_id": "$_id.hubId",
"statusCounts": {
"$push": {
"k": "$_id.status",
"v": "$count"
}
}
} },
{ "$lookup": {
"fron": "users",
"localField": "_id",
"foreignField": "_id",
"as": "user"
} },
{ "$project": {
"user": { "$arrayElemAt": ["$user", 0] },
// "hub": { "$first": "$hub" },
"statusCounts": { "$arrayToObject": "$statusCounts" }
} }
])
To project only some fields in the user profile, you can update your $lookup pipeline to have the form
{ "$lookup": {
"from": "users",
"let": { "userId": "$_id" },
"pipeline": [
{ "$match": {
"$expr": { "$eq": ["$_id", "$$userId"] }
} },
{ "$project": {
"name": 1,
"phone": 1,
"photo": 1
} }
],
"as": "user"
} }