How to transform MongoDB document to tree structure by Aggregation? [duplicate] - mongodb

I'm working in a REST api with ExpressJS and Mongo and I have a collection with N quantity of levels.
So to solve this problem I'm using an recursive table (or collection) in mongo where a field is the id and every register has a parent_id which is at the same level as it's childs.
To explain better this, here is an E-R representation
So as you se, mongo will save the data like this json (accounts level 0 has null parent)
[
{ "id": "45TYYU", "parent_id": null, "name":"account 1", "type": 1, "category": 1 },
{ "id": "45TYYXT", "parent_id": "45TYYU", "name":"account 2", "type": 1, "category": 1 },
{ "id": "45TYYPZ", "parent_id": "45TYYU", "name":"account 3", "type": 1, "category": 1 },
{ "id": "45TYYPZRE", "parent_id": "45TYYPZ", "name":"account 4", "type": 1, "category": 1 },
{ "id": "45TYYPZSX", "parent_id": "45TYYPZ", "name":"account 5", "type": 1, "category": 1 },
{ "id": "45TYYPZGP", "parent_id": "45TYYXT", "name":"account 6", "type": 1, "category": 1 }
]
account 2 and account 3 are children of account 1, while account 4 and account 5 are children of account tree and account 6 is child of account 2 ... but every register is at the same logical level only identifying through parent_id.
so I need to transform this data into a GET method to restructure it like this:
[
{
"id": "45TYYU",
"parent_id": null,
"name":"account 1",
"type": 1,
"category": 1,
"children": [
{
"id": "45TYYXT",
"parent_id": "45TYYU",
"name":"account 2",
"type": 1,
"category": 1,
"children": [
{ "id": "45TYYPZGP", "parent_id": "45TYYXT", "name":"account 6", "type": 1, "category": 1 }
]
},
{
"id": "45TYYPZ",
"parent_id": "45TYYU",
"name":"account 3",
"type": 1,
"category": 1,
"children": [
{ "id": "45TYYPZRE", "parent_id": "45TYYPZ", "name":"account 4", "type": 1, "category": 1 },
{ "id": "45TYYPZSX", "parent_id": "45TYYPZ", "name":"account 5", "type": 1, "category": 1 }
]
}
]
},
{
"id": "45TFJK",
"parent_id": null,
"name":"account 7",
"type": 1,
"category": 1,
"children": [
{
"id": "47HJJT",
"parent_id": "45TFJK",
"name":"account 8",
"type": 1,
"category": 1
},
{
"id": "47YHJU",
"parent_id": "45TFJK",
"name":"account 8",
"type": 1,
"category": 1
}
]
}
]
Yes... the parents level 0 has null parent_id and I want to put it's children inside an array called "children" and then send like this in the GET response to my UI
What is the best way to do this in expressJS?
Is there a library or component out there that allows me to do this?
Thank you

You can use $graphLookup and other useful array operators,
$match filter that records only have parent_id is null
$graphLookup to get child records and depth number in depthField level
$unwind deconstruct children array and allow to not remove empty children
$sort by depth level field level in descending order
$group by id field and reconstruct children array
db.collection.aggregate([
{ $match: { parent_id: null } },
{
$graphLookup: {
from: "collection",
startWith: "$id",
connectFromField: "id",
connectToField: "parent_id",
depthField: "level",
as: "children"
}
},
{
$unwind: {
path: "$children",
preserveNullAndEmptyArrays: true
}
},
{ $sort: { "children.level": -1 } },
{
$group: {
_id: "$id",
parent_id: { $first: "$parent_id" },
name: { $first: "$name" },
type: { $first: "$type" },
category: { $first: 1 },
children: { $push: "$children" }
}
},
$addFields now find the nested level children and allocate to its level,
$reduce to iterate loop of children array.
initialize default field level default value is -1, presentChild is [], prevChild is [] for the conditions purpose
$let to initialize fields:
prev as per condition if both level are equal then return prevChild otherwise return presentChild
current as per condition if both level are equal then return presentChild otherwise []
in to return level field and prevChild field from initialized fields
presentChild $filter children from prev array and return, merge current objects with children array using $mergeObjects and concat with current array of let using $concatArrays
$addFields to return only presentChild array because we only required that processed array
{
$addFields: {
children: {
$reduce: {
input: "$children",
initialValue: { level: -1, presentChild: [], prevChild: [] },
in: {
$let: {
vars: {
prev: {
$cond: [
{ $eq: ["$$value.level", "$$this.level"] },
"$$value.prevChild",
"$$value.presentChild"
]
},
current: {
$cond: [{ $eq: ["$$value.level", "$$this.level"] }, "$$value.presentChild", []]
}
},
in: {
level: "$$this.level",
prevChild: "$$prev",
presentChild: {
$concatArrays: [
"$$current",
[
{
$mergeObjects: [
"$$this",
{
children: {
$filter: {
input: "$$prev",
as: "e",
cond: { $eq: ["$$e.parent_id", "$$this.id"] }
}
}
}
]
}
]
]
}
}
}
}
}
}
}
},
{
$addFields: {
id: "$_id",
children: "$children.presentChild"
}
}
])
Playground

#turivishal Im using same schema in backend nodejs im getting only show the
null object not for a parent child relation using same aggregration
this.tickets.aggregate([
{
$match: {
parent_id: null
}
},
{
$graphLookup: {
from: "collection",
startWith: "$id",
connectFromField: "id",
connectToField: "parent_id",
depthField: "level",
as: "children"
}
},
{
$unwind: {
path: "$children",
preserveNullAndEmptyArrays: true
}
},
{
$sort: {
"children.level": -1
}
},
{
$group: {
_id: "$id",
parent_id: {
$first: "$parent_id"
},
name: {
$first: "$name"
},
type: {
$first: "$type"
},
category: {
$first: 1
},
children: {
$push: "$children"
}
}
},
{
$addFields: {
children: {
$reduce: {
input: "$children",
initialValue: {
level: -1,
presentChild: [],
prevChild: []
},
in: {
$let: {
vars: {
prev: {
$cond: [
{
$eq: [
"$$value.level",
"$$this.level"
]
},
"$$value.prevChild",
"$$value.presentChild"
]
},
current: {
$cond: [
{
$eq: [
"$$value.level",
"$$this.level"
]
},
"$$value.presentChild",
[]
]
}
},
in: {
level: "$$this.level",
prevChild: "$$prev",
presentChild: {
$concatArrays: [
"$$current",
[
{
$mergeObjects: [
"$$this",
{
children: {
$filter: {
input: "$$prev",
as: "e",
cond: {
$eq: [
"$$e.parent_id",
"$$this.id"
]
}
}
}
}
]
}
]
]
}
}
}
}
}
}
}
},
{
$addFields: {
children: "$children.presentChild"
}
}
]).then((result) => {
console.log('test',result);
// callback(result);
}).catch((error) => {
callback(error);
});
output:
[
{
_id: '45TYYU',
parent_id: null,
name: 'account 1',
type: 1,
category: 1,
children: []
},
{
_id: '45TYYUA',
parent_id: null,
name: 'account 1',
type: 1,
category: 1,
children: []
}
]

Related

MongoDB Complex Aggregation - Combined Sum & Count

I have a DB in which each document has an array of many different objects, of which I'm interested in working with only 6 specific ones. 5 of which are integers and 1 is categorical (text).
In order to leave only the fields I need for the aggregation, I've used $unwind on the fields array - multiplying each document by the number of fields it has. After this I filtered the specific fields I want using a basic $match.
This is where I hit some trouble - I've managed to write two queries where each gives me half of the end result I need. But I'm unable to combine them together into one general query. Specifically, I have one query that gives me 5 integer fields, each is the $sum of each integer fields, and another query that uses the categorical field in order to $count the number of times each category appears.
The desired output would give me a single document that has 5 k:v fields (1 for each sum calculation), and an additional object that includes k:v fields (where each key is a category and the value is the number of times it appears. this must be its own object because the categories that appear may vary).
The sample data I've added has been striped of most of it's structure and includes only the crucial parts relevant for this query. This is in order to secure our clients privacy.
I've tried solving this from every angle I could think of - and would greatly appreciate any feedback!
The first query:
[{$match: {
fields: {
$elemMatch: {
field_id: 174196148,
'values.start': {
$gte: ISODate('2022-02-01T00:00:00.000Z'),
$lt: ISODate('2022-02-03T00:00:00.000Z')
}
}
}
}}, {$unwind: {
path: '$fields'
}}, {$match: {
$or: [
{
'fields.field_id': 226577699
},
{
'fields.field_id': 225330844
},
{
'fields.field_id': 158472699
},
{
'fields.field_id': 191195626
},
{
'fields.field_id': 219444876
}
]
}}, {$unwind: {
path: '$fields.values'
}}, {$addFields: {
'Specific - Field Value': {
$round: [
{
$toDecimal: '$fields.values.value'
}
]
}
}}, {$group: {
_id: '$fields.label',
SumCalculation: {
$sum: {
$toDecimal: '$Specific - Field Value'
}
}
}}, {$group: {
_id: null,
SumArray: {
$push: {
k: '$_id',
v: '$SumCalculation'
}
}
}}, {$project: {
_id: 0,
Final: {
$arrayToObject: '$SumArray'
}
}}]
The second query:
[{$match: {
fields: {
$elemMatch: {
field_id: 174196148,
'values.start': {
$gte: ISODate('2022-01-01T00:00:00.000Z'),
$lt: ISODate('2022-03-31T00:00:00.000Z')
}
}
}
}}, {$unwind: {
path: '$fields'
}}, {$match: {
'fields.field_id': 177278285
}}, {$unwind: {
path: '$fields.values'
}}, {$group: {
_id: '$fields.values.value.text',
ModelCount: {
$sum: 1
}
}}, {$group: {
_id: null,
Full: {
$push: {
k: '$_id',
v: '$ModelCount'
}
}
}}, {$project: {
_id: 0,
Final: {
$arrayToObject: '$Full'
}
}}]
The desired output:
{
"Final": {
"Business Model": [
{
"K": "Solar Lease",
"V": 3
},
{
"K": "Solar Purchase",
"V": 112
}
],
"System Size - Signed Contract": 73,
"Additional Payment for O&M": 2000,
"O&M Years Included (Paid)": 2,
"Total Price Including VAT": 396660,
"1st Milestone - Down Payment": 30280
}
}
Sample data:
{
"_id": 1946794344,
"fields": [
{
"type": "money",
"field_id": 226577699,
"label": "1st Milestone - Down Payment ",
"values": [
{
"currency": "ILS",
"value": "6120.0000"
}
],
"config": {
"settings": {
"allowed_currencies": [
"ILS"
]
},
"mapping": null,
"label": "1st Milestone - Down Payment "
},
"external_id": "1st-milestone-down-payment-2"
},
{
"type": "money",
"field_id": 225330844,
"label": "Additional Payment for O&M",
"values": [
{
"currency": "ILS",
"value": "0.0000"
}
],
"config": {
"settings": {
"allowed_currencies": [
"ILS"
]
},
"mapping": null,
"label": "Additional Payment for O&M"
},
"external_id": "additional-payment-for-om"
},
{
"type": "money",
"field_id": 158472699,
"label": "Total Price Including VAT",
"values": [
{
"currency": "ILS",
"value": "61270.0000"
}
],
"config": {
"settings": {
"allowed_currencies": [
"ILS"
]
},
"mapping": null,
"label": "Total Price Including VAT"
},
"external_id": "money"
},
{
"type": "number",
"field_id": 191195626,
"label": "System Size - Signed Contract",
"values": [
{
"value": "11.6600"
}
],
"config": {
"settings": {
"decimals": 2
},
"mapping": null,
"label": "System Size - Signed Contract"
},
"external_id": "hspq-hmrkt"
},
{
"type": "number",
"field_id": 219444876,
"label": "O&M Years Included (Paid)",
"values": [
{
"value": "0.0000"
}
],
"config": {
"settings": {
"decimals": 0
},
"mapping": null,
"label": "O&M Years Included (Paid)"
},
"external_id": "om-years-gifted-for-free"
},
{
"type": "category",
"field_id": 177278285,
"label": "Business Model",
"values": [
{
"value": {
"status": "active",
"text": "Solar Purchase",
"id": 6,
"color": "DCEBD8"
}
}
],
"external_id": "mvdl-sqy"
}
]
}

Group Subdocuments Array by key in MongoDB

Is it possible to use MongoDB's aggregation framework to group channels using folder key and without joining documents?
[{key: 1, channels: {A: [], B: [], etc}}, {key: 2, channels: {A: [], B: [], etc}}]
I am trying to do using $unwind and then $group by folder name but it seems impossible.
Mongo Playground
Documents:
[
{
key: 1,
channels: [
{
"id": 1,
"name": "XXX",
"folder": "C"
},
{
"id": 2,
"name": "XXX",
"folder": "A"
},
{
"id": 3,
"name": "XXX",
"folder": "B"
},
{
"id": 4,
"name": "XXX",
"folder": "A"
},
{
"id": 5,
"name": "XXX",
"folder": "B"
},
{
"id": 6,
"name": "XXX",
"folder": "C"
}
]
},
{
key: 2,
channels: [
{
"id": 1,
"name": "XXX",
"folder": "D"
},
{
"id": 2,
"name": "XXX",
"folder": "B"
},
{
"id": 3,
"name": "XXX",
"folder": "A"
},
{
"id": 4,
"name": "XXX",
"folder": "C"
},
{
"id": 5,
"name": "XXX",
"folder": "A"
},
{
"id": 6,
"name": "XXX",
"folder": "D"
}
]
}
]
Expected Result:
[
{
key: 1,
channels: {
A: [{
"id": 2,
"name": "XXX"
},{
"id": 4,
"name": "XXX"
}],
B: [{
"id": 3,
"name": "XXX"
}, {
"id": 5,
"name": "XXX"
}],
C: [{
"id": 1,
"name": "XXX"
},{
"id": 6,
"name": "XXX"
}]
}
},
{
"key": 2,
"channels": ...
}
]
Thank you very much in advance.
$group by key and folder, construct channels array by providing required fields
$group by only key and construct the channels array in key-vlaue format
$arrayToObject convert above constructed channels to object
db.collection.aggregate([
{ $match: { key: { $in: [1, 2] } } },
{ $unwind: "$channels" },
{
$group: {
_id: {
id: "$key",
folder: "$channels.folder"
},
channels: {
$push: {
id: "$channels.id",
name: "$channels.name"
}
}
}
},
{
$group: {
_id: "$_id.id",
channels: {
$push: {
k: "$_id.folder",
v: "$channels"
}
}
}
},
{ $project: { channels: { $arrayToObject: "$channels" } } }
])
Playground
You just have to add one more $group stage followed by project stage which will alter the data as per requirement.
db.collection.aggregate([
{
$match: {
key: {
$in: [
1,
2
]
}
}
},
{
$unwind: "$channels"
},
{
$group: {
_id: {
key: "$key",
folder: "$channels.folder"
},
value: {
$push: "$channels",
},
"foldersRef": {
$push: "$channels.folder"
},
}
},
{
$group: {
_id: "$_id.key",
"channels": {
"$push": "$value"
},
},
},
{
"$project": {
"channels": {
"$map": {
"input": "$channels",
"as": "channel",
"in": {
"$arrayToObject": [
[
{
"v": {
"$map": {
"input": "$$channel",
"as": "subChannel",
"in": {
"id": "$$subChannel.id",
"name": "$$subChannel.name",
}
}
},
"k": {
"$arrayElemAt": [
"$$channel.folder",
0
]
},
}
]
],
},
}
},
},
},
])
Mongo Playground Sample Execution
What you have done is more appreciated. You might need two grop to easly preform the aggregations
$unwind to deconstruct the array
$group to group by key and foldername and second group to group by key only, but make the grp as key value pair which helps for $arrayToObject
$replaceRoot to make it to root with other fields _id ($mergeobjects)
$project for projection
Here is the code
db.collection.aggregate([
{ $unwind: "$channels" },
{
"$group": {
"_id": { key: "$key", fname: "$channels.folder" },
"channels": { "$push": "$channels" }
}
},
{
"$group": {
"_id": "$_id.key",
"grp": { "$push": { k: "$_id.fname", v: "$channels" } }
}
},
{ "$addFields": { "grp": { "$arrayToObject": "$grp" } } },
{
"$replaceRoot": {
"newRoot": { "$mergeObjects": [ "$grp", "$$ROOT" ] }
}
},
{
"$project": { grp: 0 }
}
])
Working Mongo playground

MongoDb aggregation with arrays inside an array possible

I am struggling to find some examples of using the mongo aggregation framework to process documents which has an array of items where each item also has an array of other obejects (array containing an array)
In the example document below what I would really like is an example that sums the itemValue in the results array of all cases in the document and accross the collection where the result.decision was 'accepted'and group by the document locationCode
However, even an example that found all documents where the result.decision was 'accepted' to show or that summmed the itemValue for the same would help
Many thanks
{
"_id": "333212",
"data": {
"locationCode": "UK-555-5566",
"mode": "retail",
"caseHandler": "A N Other",
"cases": [{
"caseId": "CSE525666",
"items": [{
"id": "333212-CSE525666-1",
"type": "hardware",
"subType": "print cartridge",
"targetDate": "2020-06-15",
"itemDetail": {
"description": "acme print cartridge",
"quantity": 2,
"weight": "1.5"
},
"result": {
"decision": "rejected",
"decisionDate": "2019-02-02"
},
"isPriority": true
},
{
"id": "333212-CSE525666-2",
"type": "Stationery",
"subType": "other",
"targetDate": "2020-06-15",
"itemDetail": {
"description": "staples box",
"quantity": 3,
"weight": "1.66"
},
"result": {
"decision": "accepted",
"decisionDate": "2020-03-03",
"itemValue": "23.01"
},
"isPriority": true
}
]
},
{
"caseId": "CSE885655",
"items": [{
"id": "333212-CSE885655-1",
"type": "marine goods",
"subType": "fish food",
"targetDate": "2020-06-04",
"itemDetail": {
"description": "fish bait",
"quantity": 5,
"weight": "0.65"
},
"result": {
"decision": "accepted",
"decisionDate": "2020-03-02"
},
"isPriority": false
},
{
"id": "333212-CSE885655-4",
"type": "tobacco products",
"subType": "cigarettes",
"deadlineDate": "2020-06-15",
"itemDetail": {
"description": "rolling tobbaco",
"quantity": 42,
"weight": "2.25"
},
"result": {
"decision": "accepted",
"decisionDate": "2020-02-02",
"itemValue": "48.15"
},
"isPriority": true
}
]
}
]
},
"state": "open"
}
You're probably looking for $unwind. It takes an array within a document and creates a separate document for each array member.
{ foos: [1, 2] } -> { foos: 1 }, { foos: 2}
With that you can create a flat document structure and match & group as normal.
db.collection.aggregate([
{
$unwind: "$data.cases"
},
{
$unwind: "$data.cases.items"
},
{
$match: {
"data.cases.items.result.decision": "accepted"
}
},
{
$group: {
_id: "$data.locationCode",
value: {
$sum: {
$toDecimal: "$data.cases.items.result.itemValue"
}
}
}
},
{
$project: {
_id: 0,
locationCode: "$_id",
value: "$value"
}
}
])
https://mongoplayground.net/p/Xr2WfFyPZS3
Alternative solution...
We group by data.locationCode and sum all items with this condition:
cases[*].items[*].result.decision" == "accepted"
db.collection.aggregate([
{
$group: {
_id: "$data.locationCode",
itemValue: {
$sum: {
$reduce: {
input: "$data.cases",
initialValue: 0,
in: {
$sum: {
$concatArrays: [
[ "$$value" ],
{
$map: {
input: {
$filter: {
input: "$$this.items",
as: "f",
cond: {
$eq: [ "$$f.result.decision", "accepted" ]
}
}
},
as: "item",
in: {
$toDouble: {
$ifNull: [ "$$item.result.itemValue", 0 ]
}
}
}
}
]
}
}
}
}
}
}
}
])
MongoPlayground

MongoDB multiple counts, single document, arrays

I have been searching on stackoverflow and cannot find exactly what I am looking for and hope someone can help. I want to submit a single query, get multiple counts back, for a single document, based on array of that document.
My data:
db.myCollection.InsertOne({
"_id": "1",
"age": 30,
"items": [
{
"id": "1",
"isSuccessful": true,
"name": null
},{
"id": "2",
"isSuccessful": true,
"name": null
},{
"id": "3",
"isSuccessful": true,
"name": "Bob"
},{
"id": "4",
"isSuccessful": null,
"name": "Todd"
}
]
});
db.myCollection.InsertOne({
"_id": "2",
"age": 22,
"items": [
{
"id": "6",
"isSuccessful": true,
"name": "Jeff"
}
]
});
What I need back is the document and the counts associated to the items array for said document. In this example where the document _id = "1":
{
"_id": "1",
"age": 30,
{
"totalIsSuccessful" : 2,
"totalNotIsSuccessful": 1,
"totalSuccessfulNull": 1,
"totalNameNull": 2
}
}
I have found that I can get this in 4 queries using something like this below, but I would really like it to be one query.
db.test1.aggregate([
{ $match : { _id : "1" } },
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$items",
"cond": { "$eq": [ "$$this.isSuccessful", true ] }
}
}
}
}}
])
Thanks in advance.
I am assuming your expected result is invalid since you have an object literal in the middle of another object and also you have totalIsSuccessful for id:1 as 2 where it seems they should be 3. With that said ...
you can get similar output via $unwind and then grouping with $sum and $cond:
db.collection.aggregate([
{ $match: { _id: "1" } },
{ $unwind: "$items" },
{ $group: {
_id: "_id",
age: { $first: "$age" },
totalIsSuccessful: { $sum: { $cond: [{ "$eq": [ "$items.isSuccessful", true ] }, 1, 0 ] } },
totalNotIsSuccessful: { $sum: { $cond: [{ "$ne": [ "$items.isSuccessful", true ] }, 1, 0 ] } },
totalSuccessfulNull: { $sum: { $cond: [{ "$eq": [ "$items.isSuccessful", null ] }, 1, 0 ] } },
totalNameNull: { $sum: { $cond: [ { "$eq": [ "$items.name", null ]}, 1, 0] } } }
}
])
The output would be this:
[
{
"_id": "_id",
"age": 30,
"totalIsSuccessful": 3,
"totalNameNull": 2,
"totalNotIsSuccessful": 1,
"totalSuccessfulNull": 1
}
]
You can see it working here

How to use conditional count while doing grouping in mongodb?

I need help in getting counts in the conditional grouping.
I have following JSON
[
{
"id": "103303dd56a731e377d01f6a37badae3",
"project_id": "10006",
"project_name": "Project_6",
"status": "TERM"
},
{
"id": "b63826f7edd2fc3ad8449add0c04fceb",
"project_id": "10004",
"project_name": "Project_4",
"status": "CMP"
},
{
"id": "d46e1fcf4c07ce4a69ee07e4134bcef1",
"project_id": "10008",
"project_name": "Project_8",
"status": "TERM"
},
{
"id": "a9fb9e6ef40426e9add520623d521ab8",
"project_id": "10001",
"project_name": "Project_1",
"status": "TERM"
},
{
"id": "b63826f7edd2fc3ad8449add0c04fceb",
"project_id": "10004",
"project_name": "Project_4",
"status": "QF"
}]
So you can see I have Duplicate Projects Records.
I want to get Data like this.
[
{
"project_id": "10007",
"starts": 2, //Count of records where project grouped
"Completes":3 //Where status="CMP"
"TERMS":6 //Where status="TERM"
"QFull":2 //Where status="QF",
"Abandons":3 //Where status=""
},
{
"project_id": "10004",
"starts": 3, //Count of records where project grouped
"Completes":2 //Where status="CMP"
"TERMS":4 //Where status="TERM"
"QFull":2 //Where status="QF",
"Abandons":1 //Where status=""
},
{
"project_id": "10001",
"starts": 3, //Count of records where project grouped
"Completes":2 //Where status="CMP"
"TERMS":4 //Where status="TERM"
"QFull":2 //Where status="QF",
"Abandons":1 //Where status=""
}
]
Here is the Fiddle for same: https://mongoplayground.net/p/yNerdPRjbxc
What I've tried so far:
db.collection.aggregate([
{
$group: {
_id: {
project_id: "$project_id"
},
project_id: {
$first: "$project_id"
},
starts: {
$sum: 1
}
}
}
])
I am not sure how can I add extra fields here based on conditions.
There is a $cond operator which can be used within $sum. So you simply add 1 if status matches your condition or 0 if it doesn't. You can try below aggregation:
db.col.aggregate([
{
$group: {
_id: "$project_id",
starts: { $sum: 1 },
Completes: { $sum: { $cond: [ { $eq: [ "$status", "CMP" ] }, 1, 0 ] } },
TERMS: { $sum: { $cond: [ { $eq: [ "$status", "TERM" ] }, 1, 0 ] } },
QFull: { $sum: { $cond: [ { $eq: [ "$status", "QF" ] }, 1, 0 ] } },
Abandons: { $sum: { $cond: [ { $eq: [ "$status", "" ] }, 1, 0 ] } },
}
},
{
$project: {
_id: 0,
project_id: "$_id",
starts: 1,
Completes: 1,
TERMS: 1,
QFull: 1,
Abandons: 1
}
}
])
Here is a Fiddle for the same: https://mongoplayground.net/p/JOZJOhyrnRL
this fiddle contains $match as well if you want to retrieve records for specific projects