Mongodb aggregate query issue - mongodb

I have the following query which is supposed to be getting, for each state, the amount of flights that fly within the state. Basically, the origin state and the destination state are the same. Pretty straightforward.
function(){
return db.flight_info.aggregate([
{ $project: { matches: { $eq:[ '$ORIGIN_STATE_ABR', '$DEST_STATE_ABR' ] }} },
{ $match: { matches:true } },
{ $group: { _id: "$ORIGIN_STATE_ABR", total: {$sum: 1} } }
]);
}
The issue is that this is not actually grouping my data for some reason. The output simply looks like this:
{
"_id": null,
"total": 61402
}
while it should be something along the lines of:
{
{"_id": "FL",
"total": 620 },
{"_id": "GA",
"total": 896},
...
}

You're missing the ORIGIN_STATE_ABR in your $project and that's causing an issue in your grouping.
db.flight_info.aggregate([
{ $project: { ORIGIN_STATE_ABR: 1,
matches: { $eq:[ '$ORIGIN_STATE_ABR', '$DEST_STATE_ABR' ] } } },
{ $match: { matches:true } },
{ $group: { _id: "$ORIGIN_STATE_ABR", total: { $sum: 1 } } }
]);

Related

How to group mongodb aggregate array of objects data To sum numbers on the same date

I'm trying to create charts but I can't combine the data to be like "Expected result below"
What can I use to return "Expected result".
I tried using $group in $group and $reduce and it didn't work well.
I hope someone can help me solve this task
Current result is
[
{
"_id":"5fd4c3586e83b334d97c5218",
"consumption":5,
"charts":[
{
"date":"2020-10",
"consumption":1
},
{
"date":"2020-10",
"consumption":1
},
{
"date":"2020-11",
"consumption":1
},
{
"date":"2020-11",
"consumption":1
}
]
}
]
Expected result is
[
{
"_id":"5fd4c3586e83b334d97c5218",
"consumption":5,
"charts":[
{
"date":"2020-10",
"consumption":2
},
{
"date":"2020-11",
"consumption":2
},
}
]
You need to go with aggregations
db.collection.aggregate([
{ $unwind: "$charts" },
{
$group: {
_id: { _id: "$_id", month: "$charts.date.month", year: "$charts.date.year" },
consumption: { $first: "$consumption" },
total: { $sum: "$charts.consumption" },
date: { $first: "$charts.date" }
}
},
{
$group: {
_id: "$_id._id",
consumption: { $first: "$consumption" },
charts: {
$push: {
date: "$date",
consumption: "$total"
}
}
}
}
])
Working Mongo playground

Mongodb aggregation , group by items for the last 5 days

I'm trying to get the result in some form using mongodb aggregation.
here is my sample document in the collection:
[{
"_id": "34243243243",
"workType": "TESTWORK1",
"assignedDate":ISODate("2021-02-22T00:00:00Z"),
"status":"Completed",
},
{
"_id": "34243243244",
"workType": "TESTWORK2",
"assignedDate":ISODate("2021-02-21T00:00:00Z"),
"status":"Completed",
},
{
"_id": "34243243245",
"workType": "TESTWORK3",
"assignedDate":ISODate("2021-02-20T00:00:00Z"),
"status":"InProgress",
}...]
I need to group last 5 days data in an array by workType count having staus completed.
Expected result:
{_id: "TESTWORK1" , value: [1,0,4,2,3] ,
_id: "TESTWORK2" , value: [3,9,,3,5],
_id : "TESTWORK3", value: [,,,3,5]}
Here is what I'm trying to do, but not sure how to get the expected result.
db.testcollection.aggregate([
{$match:{"status":"Completed"}},
{$project: {_id:0,
assignedSince:{$divide:[{$subtract:[new Date(),$assignedDate]},86400000]},
workType:1
}
},
{$match:{"assignedSince":{"lte":5}}},
{$group : { _id:"workType", test :{$push:{day:"$assignedSince"}}}}
])
result: {_id:"TESTWORK1": test:[{5},{3}]} - here I'm getting the day , but I need the count of the workTypes on that day.
Is there any easy way to do this? Any help would be really appreciated.
Try this:
db.testcollection.aggregate([
{
$match: { "status": "Completed" }
},
{
$project: {
_id: 0,
assignedDate: 1,
assignedSince: {
$toInt: {
$divide: [{ $subtract: [new Date(), "$assignedDate"] }, 86400000]
}
},
workType: 1
}
},
{
$match: { "assignedSince": { "$lte": 5 } }
},
{
$group: {
_id: {
workType: "$workType",
assignedDate: "$assignedDate"
},
count: { $sum: 1 }
}
},
{
$group: {
_id: "$_id.workType",
values: { $push: "$count" }
}
}
]);

total of all groups totals using mongodb

i did this Aggregate pipeline , and i want add a field contains the Global Total of all groups total.
{ "$match": query },
{ "$sort": cursor.sort },
{ "$group": {
_id: { key:"$paymentFromId"},
items: {
$push: {
_id:"$_id",
value:"$value",
transaction:"$transaction",
paymentMethod:"$paymentMethod",
createdAt:"$createdAt",
...
}
},
count:{$sum:1},
total:{$sum:"$value"}
}}
{
//i want to get
...project groups , goupsTotal , groupsCount
}
,{
"$skip":cursor.skip
},{
"$limit":cursor.limit
},
])
you need to use $facet (avaialble from MongoDB 3.4) to apply multiple pipelines on the same set of docs
first pipeline: skip and limit docs
second pipeline: calculate total of all groups
{ "$match": query },
{ "$sort": cursor.sort },
{ "$group": {
_id: { key:"$paymentFromId"},
items: {
$push: "$$CURRENT"
},
count:{$sum:1},
total:{$sum:"$value"}
}
},
{
$facet: {
docs: [
{ $skip:cursor.skip },
{ $limit:cursor.limit }
],
overall: [
{$group: {
_id: null,
groupsTotal: {$sum: '$total'},
groupsCount:{ $sum: '$count'}
}
}
]
}
the final output will be
{
docs: [ .... ], // array of {_id, items, count, total}
overall: { } // object with properties groupsTotal, groupsCount
}
PS: I've replaced the items in the third pipe stage with $$CURRENT which adds the whole document for the sake of simplicity, if you need custom properties then specify them.
i did it in this way , project the $group result in new field doc and $sum the sub totals.
{
$project: {
"doc": {
"_id": "$_id",
"total": "$total",
"items":"$items",
"count":"$count"
}
}
},{
$group: {
"_id": null,
"globalTotal": {
$sum: "$doc.total"
},
"result": {
$push: "$doc"
}
}
},
{
$project: {
"result": 1,
//paging "result": {$slice: [ "$result", cursor.skip,cursor.limit ] },
"_id": 0,
"globalTotal": 1
}
}
the output
[
{
globalTotal: 121500,
result: [ [group1], [group2], [group3], ... ]
}
]

How to get top level elements as well as one level down array elements aggregate in one mongo query?

I have 2 mongo aggregate queries that work well separately -
db.transfer_orders.aggregate([
{
$match: {
"request_timestamp": { $gte: ISODate("2017-10-00T00:00:00.000Z") },
"request_timestamp": { $lt: ISODate("2017-10-12T00:00:00.000Z") },
"purpose": "POSITIONING"
}
},
{
$group: {
_id: null,
to_count: { $sum: 1 },
qty: { $sum: "$quantity" }
}
},
{
$project: {
_id: 0,
"to_count": "$to_count",
"qty": "$qty"
}
}
])
and
db.transfer_orders.aggregate([
{
$match: {
"request_timestamp": { $gte: ISODate("2017-10-00T00:00:00.000Z") },
"request_timestamp": { $lt: ISODate("2017-10-12T00:00:00.000Z") },
"purpose": "POSITIONING"
}
},
{
$unwind: "$adjustments"
},
{
$group: {
_id: null,
totalChangeQty: { $sum: "$adjustments.change_in_quantity"}
}
},
{
$project: {
_id: 0,
"adjusted_quantity": "$totalChangeQty"
}
}
])
The first query returns aggregate data of elements at the top level of the document, { "to_count" : 7810, "qty" : 19470 }
The second query returns aggregate data of elements at one level below the top level for the "adjustments" array - { "adjusted_quantity" : -960 }
Is there a way to write this as one query that will return both sets of data since the match criteria is the same for both?
The following aggregate operation should suffice since it has a pipeline after the $match step that introduces the new field adjusted_quantity. This is made possible using the $sum which returns the sum of the specified list of expressions for each document.
Once it reaches the $group stage, you can retain the value using the $sum operator.
db.transfer_orders.aggregate([
{
"$match": {
"request_timestamp": { "$gte": ISODate("2017-10-00T00:00:00.000Z") },
"request_timestamp": { "$lt": ISODate("2017-10-12T00:00:00.000Z") },
"purpose": "POSITIONING"
}
},
{
"$addFields": {
"adjusted_quantity": {
"$sum": "$adjustments.change_in_quantity"
}
}
},
{
"$group": {
"_id": null,
"to_count": { "$sum": 1 },
"qty": { "$sum": "$quantity" },
"adjusted_quantity": { "$sum": "$adjusted_quantity" }
}
}
])

Matching in MongoDB returns unwanted results

I have a collection named flights. In that collection I have two fields: origin_country and the dest_country.
These fields just keep record of the origin country and the destination country of a particular flight.
I'm trying to write a query which will return:
All theinternational flights only (i.e - where the origin and destination countries are different).
The sum of each (i.e - # of occurences of that flight in the collection).
The problem with the query which I have already is that it's also returning the domestic flights when ran:
QUERY:
db.flights.aggregate([
{$match: {
checking_countries_dont_match: { $ne: ["origin_country", "dest_country"] }
} },
{$group: {
_id: {
origin_country: "$origin_country",
dest_country: "$dest_country"
},
"count": {$sum:1}
} },
{$sort: {"count":-1} }
])
DOCUMENT SAMPLES:
{
"_id" : "2675594611",
"origin_country" : "Germany",
"dest_country" : "United Arab Emirates",
"airline_name" : "etihad-airways-etd"
}
{
"_id" : "2661517182",
"origin_country" : "Thailand",
"dest_country" : "Thailand",
"airline_name" : "nok-air-nok",
}
UPDATE
I changed the query to the following, but I still get results where the origin and destination are the same:
db.flights.aggregate([
{ $project: {
dont_match: { $ne: ["origin_country", "dest_country"] },
origin_country: "$origin_country",
dest_country: "$dest_country",
airline_name: "$airline_name"
} },
{ $match: {
airline_name: "etihad-airways-etd",
dont_match: true
} },
{ $group: {
id: {
origin_country: "$origin_country",
dest_country: "$dest_country"
}
} }
]);
UPDATE 2
Wokring Query:
db.flights.aggregate([
{ $project: {
dont_match: { $ne: ["$origin_country", "$dest_country"] },
origin_country: "$origin_country",
dest_country: "$dest_country",
airline_name: "$airline_name"
} },
{ $match: {
airline_name: "etihad-airways-etd",
dont_match: true
} },
{ $group: {
_id: {
origin_country: "$origin_country",
dest_country: "$dest_country"
},
count: {$sum:1}
} },
{ $sort: {count:-1}}
]);
Thanks for the help everyone :)
All you need to do is to modify your query a little bit. Look at this example, should give you an idea:
db.flights.aggregate([
{
$project: {
dont_match: { $ne: ["$origin_country", "$dest_country"] },
...
}
},
{
$match: {
dont_match: true
}
},
...
]);
Can you please try below query whether it match your expectation or not:
db.flights.aggregate([
{ $project: {
dont_match: {$cmp: ['$origin_country', '$dest_country']},
origin_country: "$origin_country",
dest_country: "$dest_country"
} },
{ $match: { dont_match: {$ne: 0} } }
]);