How to write sum(if a>=10 and a<=100,a,0) like SQL in mongodb - mongodb

I want to make the same SQL statement as specified select sum(if a >= 10 and a <= 100, a, 0) from table in MongoDb.
Therefore, I write:
{
"$project": {
"sumqty": {
"a1": {
"$cond": {
"if": {
"$and": [{"$gte":["$a",10]},
{"$lte":["$a",100]}]
},
"then": "$a",
"else": 0
}
}
}
}
}

Just use $cond and $group
db.table.aggregate([{
$group: {
_id: null,
totalSum: {
$sum: {
$cond: [{ $and: [{ $gte: ["$a", 10] }, { $lte: ["$a", 100] }] },
"$a",
0
]
}
}
}
}])

Related

Create a view from mongo collection

I have a mongo collection with records like
and so on.
The sample record in JSON format
[{
empId:'123',
empName:'Emp1',
shiftHours:'Regular'
},
{
empId:'123',
empName:'Emp1',
shiftHours:'Morning'
}
]
Basically an employee can work in regular shift(9am-6 pm) or morning shift (6 am-3 pm) or night shift (9pm-6 am). The hours are just example here but the idea is that the working hours are categorized in 3 shifts. I want to create a view with flat structure per employee like this
and so on.
I am trying to understand what's the best way to create such a flat view (coming from SQL background, I think a procedure/function has to be written) but not sure what's the best way to do so using No-Sql (Mongo db).
Any suggestions?
$group by empId and conditionally $sum by shiftHours.
db.collection.aggregate([
{
$group: {
_id: "$empId",
empName: {
$first: "$empName"
},
Morning: {
$sum: {
"$cond": {
"if": {
$eq: [
"$shiftHours",
"Morning"
]
},
"then": 1,
"else": 0
}
}
},
Regular: {
$sum: {
"$cond": {
"if": {
$eq: [
"$shiftHours",
"Regular"
]
},
"then": 1,
"else": 0
}
}
},
Evening: {
$sum: {
"$cond": {
"if": {
$eq: [
"$shiftHours",
"Evening"
]
},
"then": 1,
"else": 0
}
}
}
}
},
{
$set: {
Morning: {
$cond: [
{
$gt: [
"$Morning",
0
]
},
"Y",
"N"
]
},
Regular: {
$cond: [
{
$gt: [
"$Regular",
0
]
},
"Y",
"N"
]
},
Evening: {
$cond: [
{
$gt: [
"$Evening",
0
]
},
"Y",
"N"
]
}
}
}
])
Mongo Playground

How to transform an array field into a value equaling its maximum?

{
name: "use_name",
grades: [
{class: "math": grade: 100},
{class: "english": grade: 90}
]
}
How do I write an aggregation pipeline to output:
{
name: "use_name",
grades: {class: "math": grade: 100},
}
The grades field has been reduced to the element where its grade property is the maximum of all elements.
The requirements, the aggregation pipeline cannot have $unwind or $group because it cannot have a stage where the stage needs to receive all incoming documents before outputting to the next stage, potentially exceeding the 100mb limit. And it must be fast.
I think this one is faster:
db.collection.aggregate([
{
$set: {
grades: {
$first: {
$sortArray: {
input: "$grades",
sortBy: { grade: -1 }
}
}
}
}
}
])
Mongo Playground
or this one:
db.collection.aggregate([
{
$set: {
grades: {
$filter: {
input: "$grades",
cond: { $eq: [ "$$this.grade", { $max: "$grades.grade" } ] }
}
}
}
}
])
Replace $$value in $reduce until you find the max.
db.collection.aggregate([
{
$set: {
grades: {
"$reduce": {
"input": "$grades",
"initialValue": null,
"in": {
"$cond": {
"if": {
$or: [
{
$eq: [
null,
"$$value"
]
},
{
$gt: [
"$$this.grade",
"$$value.grade"
]
}
]
},
"then": "$$this",
"else": "$$value"
}
}
}
}
}
}
])
Mongo Playground

MongoDB group by and SUM by array

I'm new in mongoDB.
This is one example of record from collection:
{
supplier: 1,
type: "sale",
items: [
{
"_id": ObjectId("60ee82dd2131c5032342070f"),
"itemBuySum": 10
},
{
"_id": ObjectId("60ee82dd2131c50323420710"),
"itemBuySum": 10,
},
{
"_id": ObjectId("60ee82dd2131c50323420713"),
"itemBuySum": 10
},
{
"_id": ObjectId("60ee82dd2131c50323420714"),
"itemBuySum": 20
}
]
}
I need to group by TYPE field and get the SUM. This is output I need:
{
supplier: 1,
sales: 90,
returns: 170
}
please check Mongo playground for better understand. Thank you!
$match - Filter documents.
$group - Group by type and add item into data array which leads to the result like:
[
[/* data 1 */],
[/* data 2 */]
]
$project - Decorate output document.
3.1. First $reduce is used to flatten the nested array to a single array (from Result (2)) via $concatArrays.
3.2. Second $reduce is used to aggregate $sum the itemBuySum.
db.collection.aggregate({
$match: {
supplier: 1
},
},
{
"$group": {
"_id": "$type",
"supplier": {
$first: "$supplier"
},
"data": {
"$push": "$items"
}
}
},
{
"$project": {
_id: 0,
"supplier": "$supplier",
"type": "$_id",
"returns": {
"$reduce": {
"input": {
"$reduce": {
input: "$data",
initialValue: [],
in: {
"$concatArrays": [
"$$value",
"$$this"
]
}
}
},
"initialValue": 0,
"in": {
$sum: [
"$$value",
"$$this.itemBuySum"
]
}
}
}
}
})
Sample Mongo Playground
db.collection.aggregate([
{
$match: {
supplier: 1
},
},
{
"$group": {
"_id": "$ID",
"supplier": {
"$first": "$supplier"
},
"sale": {
"$sum": {
"$cond": {
"if": {
"$eq": [
"$type",
"sale"
]
},
"then": {
"$sum": "$items.itemBuySum"
},
"else": {
"$sum": 0
}
}
}
},
"returns": {
"$sum": {
"$sum": {
"$cond": {
"if": {
"$eq": [
"$type",
"return"
]
},
"then": {
"$sum": "$items.itemBuySum"
},
"else": {
"$sum": 0
}
}
}
}
}
}
},
{
"$project": {
_id: 0,
supplier: 1,
sale: 1,
returns: 1
}
}
])

how to use sum and condition in group using spring data mongodb aggregation

db.test.aggregate(
[ {
$group:
{
_id: "$id",
"total":{$sum: 1},
"live" : { $sum : {$cond : { if: { $eq: ["$status",A"]},then: 1, else: 0}}},
"chat_hrs" :{ $avg: { $subtract: [ "$end_time", "$start_time" ] } }}}]).
Kindly help me to write springmvc coding to use mongodb aggregation for the above query.
You can use the below aggregation pipeline.
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.core.aggregation.ArithmeticOperators.*;
import static org.springframework.data.mongodb.core.aggregation.ConditionalOperators.when;
import static org.springframework.data.mongodb.core.query.Criteria.where;
Aggregation aggregation =
newAggregation(
project("id").
and(when(where("status").is("A")).then(1).otherwise(0)).as("status").
and(Subtract.valueOf("end_time").subtract("start_time")).as("diffTime"),
group("$id").count().as("total").sum("status").as("live").avg("diffTime").as("chat_hrs"));
Generated Mongo Query:
[{
"$project": {
"id": 1,
"status": {
"$cond": {
"if": {
"$eq": ["$status", "A"]
},
"then": 1,
"else": 0
}
},
"diffTime": {
"$subtract": ["$end_time", "$start_time"]
}
}
}, {
"$group": {
"_id": "$id",
"total": {
"$sum": 1
},
"live": {
"$sum": "$status"
},
"chat_hrs": {
"$avg": "$diffTime"
}
}
}]

How to group query with multiple $cond?

I want to query like below, but this contains only one $cond.
How to query with two $cond?
collection.aggregate(
{
$match : {
'_id' : {$in:ids}
}
},
{
$group: {
_id: '$someField',
...
count: {$sum: { $cond: [ { $eq: [ "$otherField", false] } , 1, 0 ] }}
}
},
function(err, result){
...
}
);
You want to use a compound expression inside {$cond:[]} - something like:
collection.aggregate(
{
$match : {
'_id' : {$in:ids}
}
},
{
$group: {
_id: '$someField',
...
count: {$sum: { $cond: [ {$and : [ { $eq: [ "$otherField", false] },
{ $eq: [ "$anotherField","value"] }
] },
1,
0 ] }}
}
},
function(err, result){
...
}
);
The $and operator is documented here: http://docs.mongodb.org/manual/reference/operator/aggregation/#boolean-operators
you can add multiple $cond and multiple criterias inside $cond like this
`
collection.aggregate(
[
{
"$match": {
//matching criteria
}
},
{
"$project": {
"service": {
"$cond": {
"if": {
"$eq": [
"$foo",
"bar"
]
},
"then": "return string1",
"else": {
"$cond": {
"if": {
"$eq": [
"$foo",
"bar"
]
},
"then": "return string2",
"else": {
"$cond": {
"if": {
"$or": [
{
"$eq": [
"$foo",
"bar1"
]
},
{
"$eq": [
"$foo",
"bar2"
]
}
]
},
"then": "return string3",
"else": "$foo"
}
}
}
}
}
},
"_id": 0
}
}
]
)
`