MongoError: The field 'academic_year' must be an accumulator object - javascript

I have the following aggregation code which returns all the students for each school in my school ID list. For each student there is an academic year ID that looks like this: ObjectId("5ede4682341e8426f1cf6285")
return await this.studentSchoolModel.aggregate([
{
$match: {
school: { $in: schoolIDs },
},
},
{
$group: {
_id: '$school',
academic_years: '$academic_year',
total_students: { $sum: 1 },
},
},
]);
If I try to group by the school, it works, but if I try to group by the school and academic year I get the following error:
MongoError: The field 'academic_year' must be an accumulator object
Does anyone know what I'm doing wrong? I want the output for each school to look like this:
_id: 12345678 //schoolID
academic_years: {
_id: 1111111 //academic year ID
total_students: 5 //number of students in that year
},
{
_id: 2222222 //academic year ID
total_students: 8 //number of students in that year
}

You can use $group
first group is to group by school and academic year. The second group is to group by school
Here is the code
db.collection.aggregate([
{
"$group": {
"_id": { sc: "$school", ay: "$academic_year" },
total: { $sum: 1 }
}
},
{
$group: {
_id: "$_id.sc",
total_students: {
$push: {
_id: "$_id.ay",
total_students: "$total"
}
}
}
}
])
Working Mongo playground

Related

aggregation with respect to one field except one value of that field

I am writing a query to do aggregation with respect to one field, however, I want to exclude this aggregation for one value of that field
let coAuthorCutThreshold =100
network.aggregate([
{ $group: { _id: '$title', title :{$ne: "class notes"}, count: { $sum: 1 } }} ,
{ $match: { count: { $gt: coAuthorCutThreshold } } },
{ $sort: { count: -1 } }
]).forEach(function (obj) {
cutTitles.push(obj._id)
});
I want to do aggregation with respect to title but do to not want to do aggregation where the title is "class notes". I tried many command but did not work
I want to include all those values in cutTitles except where title is "class notes"
Match in order to filter out the documents you don't want to group before the group stage.
let coAuthorCutThreshold = 100
network.aggregate([
{ $match: { title: { $ne: "class notes" }}},
{ $group: { _id: '$title', count: { $sum: 1 }}},
{ $match: { count: { $gt: coAuthorCutThreshold }}},
{ $sort: { count: -1 }}
]).forEach(function (obj) {
cutTitles.push(obj._id)
});

Mongodb take only 10 firsts items of $$ROOT

I have a problem,
I do a group on my database and the problem is the $$ROOT can exceed the memory limit, so I would like to have the X first elements.
this is my group:
$group: {
_id: {
DOG_RACE: '$DOG_RACE',
FOOD: '$FOOD'
},
total: {
$count: {}
},
_raw: {
$push: '$$ROOT'
}
}
the _raw contain all dogs grouped and there can be millions.
I tried to replace _raw: {} with an array with a slice but I got this error:
The field '_raw' must be an accumulator object
Can someone please have the syntaxe to do it ?
Thanks
EDIT
No this is what I'm trying:
$group: {
_id: {
DOG_RACE: '$DOG_RACE',
FOOD: '$FOOD'
},
total: {
$count: {}
},
_raw: {
$firstN: {
input: '$$ROOT',
n: 10
}
}
}
And I'm still getting an error with MongoServerError: unknown group operator '$function'
same with $function
also my mongodb database after running mongod is v6,0,1

MongoDB Group by String Field inside of an Array

I did a lot of research on MongoDB aggregation grouping, but couldn't find a solution.
I have the following document structure:
{
"_id":"6053e0ef22b8e60015a23da8",
"shoppinglist":[
{
"_id":"606ae2e34e4416001538104f",
"items":[
{
"_id":"6071c5ed8f669f0015e6eebe",
"product_id":"605852c28ea29f0015653d6f",
},
...
]
}
}
My goal is to group the items in each shopping list object using the product_id, so that my result looks like this:
{
"_id":"6053e0ef22b8e60015a23da8",
"shoppinglist":[
{
"_id":"606ae2e34e4416001538104f",
"items":[
{
"_id":"6071c5ed8f669f0015e6eebe",
"product_id":"605852c28ea29f0015653d6f",
"count": 3 //3 items with the product_id = 605852c28ea29f0015653d6f
},
...
]
}
}
Can someone help me with this, I'm desperate.
$unwind deconstruct shoppinglist array
$unwind deconstruct shoppinglist.items array
$group by _id and product_id, and get required fields using $first and get count using $sum
$group by _id and shoppinglist._id and reconstruct array of items
$group by _id and reconstruct array of shoppinglist
db.collection.aggregate([
{ $unwind: "$shoppinglist" },
{ $unwind: "$shoppinglist.items" },
{
$group: {
_id: {
_id: "$_id",
product_id: "$shoppinglist.items.product_id"
},
shoppinglist_id: { $first: "$shoppinglist._id" },
items_id: { $first: "$shoppinglist.items._id" },
count: { $sum: 1 }
}
},
{
$group: {
_id: {
_id: "$_id._id",
shoppinglist_id: "$shoppinglist_id"
},
items: {
$push: {
items_id: "$items_id",
product_id: "$_id.product_id",
count: "$count"
}
}
}
},
{
$group: {
_id: "$_id._id",
shoppinglist: {
$push: {
_id: "$_id.shoppinglist_id",
items: "$items"
}
}
}
}
])
Playground

Get sum of values from unique docs in collection of duplicate docs in MongoDB

I am new to MongoDB and I am stuck in the below scenario.
I have a collection that contains duplicate docs.
I just want to get the sum of the property in each doc excluding the duplicate docs.
My Docs looks like this:
{"_id":"5dd629461fc50b782479ea90",
"referenceId":"5dd581f10859d2737965d23a",
"sellingId":"319723fb80b1a297cf0803abad9bc60787537f14a6a37d6e47",
"account_name":"mrfsahas1234",
"vendor_name":"testaccount2",
"action_type":"purchase",
"product_name":"Bottle",
"product_quantity":10,
"transactionId":"319723fb80b1a297cf0803abad9bc60787537f14a6a37d6e47",
"uid":"2019-11-20T17:39:17.405Z",
"createdAt":"2019-11-21T08:56:56.589+00:00",
"updatedAt":"2019-11-21T08:56:56.589+00:00","__v":0
},
{
"_id":"5dd629461fc50b782479ea90",
"referenceId":"5dd581f10859d2737965d23a",
"sellingId":"320a9a2f814a45e01eb98344c9af708fa2864d81587e5914",
"account_name":"mrfsahas1234",
"vendor_name":"testaccount2",
"action_type":"purchase",
"product_name":"Bottle",
"product_quantity":50,
"transactionId":"320a9a2f814a45e01eb98344c9af708fa2864d81587e5914",
"uid":"2019-11-20T17:39:17.405Z",
},
{
"_id":"5dd629461fc50b782479ea90",
"referenceId":"5dd581f10859d2737965d23a",
"sellingId":"320a9a2f814a45e01eb98344c9af708fa2864d81587e5914",
"account_name":"mrfsahas1234",
"vendor_name":"testaccount2",
"action_type":"purchase",
"product_name":"Bottle",
"product_quantity":50,
"transactionId":"320a9a2f814a45e01eb98344c9af708fa2864d81587e5914",
"uid":"2019-11-20T17:39:17.405Z",
},
Currently, I am doing this:
MaterialsTrack.aggregate([
{
$match: {
$and: [
{product_name: product_name},
{account_name: account_name},
{action_type: 'purchase'},
{uid:uid}
]
}
},
{
$group: {_id: "$sellingId", PurchseQuantity: {$sum: "$product_quantity"}}
},
])
It returns the sum of product_quantity all the matching docs (including the duplicate docs).
Current Output:
{_id: "320a9a2f814a45e01eb98344c9af708fa2864d81587e5914", PurchseQuantity:110}
Expected Output:
{_id: "320a9a2f814a45e01eb98344c9af708fa2864d81587e5914", PurchseQuantity:60}
I want to get the sum of only unique docs. How can I achieve it?
Thanks in advance!
You need to sum inside of the $group _id field, and then use the replaceRoot to achieve the the result you wanted.
MaterialsTrack.aggregate([
{
$match: {
$and: [
{
product_name: "Bottle"
},
{
account_name: "mrfsahas1234"
},
{
action_type: "purchase"
},
{
uid: "2019-11-20T17:39:17.405Z"
}
]
}
},
{
$group: {
_id: {
sellingId: "$sellingId",
PurchaseQuantity: {
$sum: "$product_quantity"
}
}
}
},
{
$replaceRoot: {
newRoot: {
_id: "$_id.sellingId",
PurchaseQuantity: "$_id.PurchaseQuantity"
}
}
}
]);
Sample Output:
[
{
"PurchaseQuantity": 50,
"_id": "320a9a2f814a45e01eb98344c9af708fa2864d81587e5914"
}
]
Playground:
https://mongoplayground.net/p/MOneCRiSlO0
What about adding $addToSet to your aggregations pipeline
MaterialsTrack.aggregate([
{
$match: {
$and: [
{product_name: product_name},
{account_name: account_name},
{action_type: 'purchase'},
{uid:uid}
]
}
},
{
$group: {_id: "$sellingId", PurchseQuantity: {$sum: "$product_quantity"},"list" : {$addToSet : "$list"}}
},
])

MongoDB Mongoose group by multiple fields and get the count

I've an analytics API written using MongoDB.
This is my sessions model
const sessionSchema = new Schema(
{
user: { id: Number, name: String, email: String },
},
{ timestamps: true },
);
I want to get the unique users count by the date.
for the date 2019-10-24 there maybe 10 sessions from two users (id 1, id 2)
and
for the date 2019-10-25 there maybe 20 sessions from two users (id 3, id 8)
So my expected results is
2019-10-24 2 users
2019-10-25 2 users
I tried this
db.Session.aggregate([
{
$group: {
_id: { user: '$user.id', day: { $dayOfYear: '$createdAt' } },
count: { $sum: 1 },
},
},
])
and this doesn't seem to work.
My createdAt field's type is Date (eg:- createdAt: 2019-10-16T13:11:17.935Z) That is why I used $dayOfYear: '$createdAt'
db.Session.aggregate([
{
$project: {
date: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } }
}
},
{
$group: {
_id: "$date" ,
count: { $sum: 1 }
}
}
]);
At first group according to createdAt, as we want final result according to createdAt.
In this $group stage just push the userIds into the array, use $addToSet to keep it unique.
Then get the count of userIds with $size operator in $project stage.
You get the result.
Here is the query.
(convert the date as you want, its just a format, and you have done this, so I am skipping this task).
db.sessions.aggregate({$match:{}},
{$group:{_id: "$createdAt", userId : {$addToSet: "$user.id"}}},
{$project:{_id: 1, noOfUsers:{$size:"$userId"}}}).pretty()
Hope this helps!

Categories