get sum of values from mongodb database - mongodb

this is my document in the sensor collection
sensorId:1
sensorType:1
BuildingId:1
CalcItems:
0: Object
Ts:2019-08-30T18:30:00.000+00:00
Value:1
1:Object
Ts:2019-08-31T19:00:00.000+00:00
Value:2
i need to get sum of all value attributes with respect to same Ts date value
output like this
sensorType:1
BuildingId:1
CalcItems:
0: Object
Ts:2019-08-31T18:30:00.000+00:00
Value:23
1:Object
Ts:2019-08-31T19:00:00.000+00:00
Value:43
give me any suggestions

Try this..
Sample live demo
[
{
"$unwind": "$CalcItems"
},
{
$group: {
_id: {
"sensorType": "$sensorType",
"BuildingId": "$BuildingId",
"Ts": "$CalcItems.Ts"
},
"total": {
"$sum": "$CalcItems.Value"
}
}
},
{
"$project": {
"_id": 0,
"sensorType": "$_id.sensorType",
"BuildingIdVal": "$_id.BuildingId",
"CalcItems.Ts": "$_id.Ts",
"CalcItems.Value": "$total"
}
}
]
Reference
Mongodb $sum
Mongodb $group
Mongodb $project

Related

Mongo projection for only field and value

I have large documents and I want to project them with only field and value.
It goes like this;
{"p":{"s":{"status":"b"},"m":{"pd":{"tt":{"bi":"2","psi":"4","ircsi":true}},"mi":"TT","et":"2020-09-07T14:34:00+03:00"}}}
{"p":{"s":{"status":"b"},"m":{"pd":{"tt":{"bi":"20","psi":"1","ircsi":true}},"mi":"TT","et":"2020-12-29T08:28:06+03:00"}}}
.........
Is there any way for its to look like this;
{"status":"b","bi":"2","psi":"4","ircsi":true,"mi":"TT","et":"2020-09-07T14:34:00+03:00"}}}
{"status":"b","bi":"20","psi":"1","ircsi":true,"mi":"TT","et":"2020-09-07T14:34:00+03:00"}}}
.........
And my query is like this;
db.s.aggregate([{
"$match": {
"p.m.etm": {
"$gt": 1585688401000,
"$lt": 1610565947499
},
"p.m.mi":"TT"
}
},
{
"$project": {
"p.m.pd.tt.bi": 1,
"p.m.pd.tt.psi": 1,
"p.m.pd.tt.ircsi": 1,
"p.m.mi":1,
"p.s.status":1,
"p.m.et":1,
"_id": 0
}
}],
{
"allowDiskUse": true
});
What should I change to reach what I need ?
You can use $project to create new fields. (I just remove $match for easiness)
db.collection.aggregate([
{
"$project": {
"bi": "$p.m.pd.tt.bi",
"psi": "$p.m.pd.tt.psi",
"ircsi": "$p.m.pd.tt.ircsi",
"mi": "$p.m.mi",
"status": "$p.s.status",
"et": "$p.m.et",
"_id": 0
}
}
])
Working Mongo playground

Is there a way to give order field to the result of MongoDB aggregation?

Is there any way to give order or rankings to MongoDB aggregation results?
My result is:
{
"score":100
"name": "John"
},
{
"score":80
"name": "Jane"
},
{
"score":60
"name": "Lee"
}
My wanted result is:
{
"score":100
"name": "John",
"rank": 1
},
{
"score":80
"name": "Jane"
"rank": 2
},
{
"score":60
"name": "Lee"
"rank": 3
}
I know there is a operator called $includeArrayIndex but this only works with $unwind operator.
Is there any way to give rank without using $unwind?
Using $unwind requires grouping on my collection, and I'm afraid grouping pipeline would be too huge to process.
The other way is to use $map and add rank in document using its index, and don't use $unwind stage because it would be single field array you can directly access using its key name as mention in last line of code,
$group by null and make array of documents in root array,
$map to iterate loop of root array, get the index of current object from root array using $indexOfArray and increment that returned index number using $add because index start from 0, and that is how we are creating rank field, merge object with current element object and rank field using $mergeObjects
let result = await db.collection.aggregate([
{
$group: {
_id: null,
root: {
$push: "$$ROOT"
}
}
},
{
$project: {
_id: 0,
root: {
$map: {
input: "$root",
in: {
$mergeObjects: [
"$$this",
{
rank: { $add: [{ $indexOfArray: ["$root", "$$this"] }, 1] }
}
]
}
}
}
}
}
]);
// you can access result using root key
let finalResult = result[0]['root'];
Playground

MongoDB $push aggregaton won't keep the right order

I tried to make a $group aggregation with MongoDB, like the following example:
"$group": {
"_id": "$test_id",
"feeling": {
"$push": "$feeling"
},
"reference_id": {
"$push": "$_id"
},
"training_start": {
"$push": "$training_start"
},
"training_duration": {
"$push": "$duration_ms"
}
}
The aggregation works fine, but the created arrays are sorted different. That means, if I check the result of the aggregation by looking at reference_id[x] and training_start[x] then the value of training_start in the source collection is not equal to training_start[x].
Maybe an example shows my problem more precisely:
One document after the $group aggregation:
{
_id: "string_1",
reference_id: [1, 2, 3],
training_start: [01:00:00, 02:00:00, 03:00:00] (date times)
}
Documents from source collection:
{
_id:1,
training_start: 01:00:00,
test_id: "string_1"
},
{
_id:2,
training_start: 03:00:00,
test_id: "string_1"
},
{
_id:3,
training_start: 02:00:00,
test_id: "string_1"
}
The first elements in these arrays are always in the right order. So I checked if each grouped field has the same number of entries by using the code below. And the annoying result is, that the amount of entries in each array is equal. So there is no shift in the arrays caused by missing values.
"$group": {
"_id": "$test_id",
"sum": {
"$sum": {
"$cond": {
"if": {
"$lte": [
"$training_start", null
]
},
"then": 0,
"else": 1
}
}
}
Does anybody know, if there is an other way to create arrays (already tried $addToSet) which keep the order, the elements where pushed in? Or am I the problem?
Greetings Max

mongodb - $sort child documents only

When i do a find all in a mongodb collection, i want to get maintenanceList sorted by older maintenanceDate to newest.
The sort of maintenanceDate should not affect parents order in a find all query
{
"_id":"507f191e810c19729de860ea",
"color":"black",
"brand":"brandy",
"prixVenteUnitaire":200.5,
"maintenanceList":[
{
"cost":100.40,
"maintenanceDate":"2017-02-07T00:00:00.000+0000"
},
{
"cost":4000.40,
"maintenanceDate":"2019-08-07T00:00:00.000+0000"
},
{
"cost":300.80,
"maintenanceDate":"2018-08-07T00:00:00.000+0000"
}
]
}
Any guess how to do that ?
Thank you
Whatever order the fields are in with the previous pipeline stage, as operations like $project and $group effectively "copy" same position.So, it will not change the order of your fields in your aggregated result.
And the sort of maintenanceDate through aggregation will not affect parents order in a find all query.
So, simply doing this should work.
Assuming my collection name is example.
db.example.aggregate([
{
"$unwind": "$maintenanceList"
},
{
"$sort": {
"_id": 1,
"maintenanceList.maintenanceDate": 1
}
},
{
"$group": {
"_id": "$_id",
"color": {
$first: "$color"
},
"brand": {
$first: "$brand"
},
"prixVenteUnitaire": {
$first: "$prixVenteUnitaire"
},
"maintenanceList": {
"$push": "$maintenanceList"
}
}
}
])
Output:

mongo query to aggregate 2 documents for 2 dates

i have following collection...
[{
"_id":"abcd1234",
"Date" :{"$date":1430418601000},
"Count":{
"hr1":0,
"hr2":20,
"hr3":1,
"hr4":4,
"hr5":0,
}
},
{
"_id":"abcd1234",
"Date" :{"$date":1430505001000},
"Count":{
"hr1":2,
"hr2":15,
"hr3":15,
"hr4":0,
"hr5":1,
}
}
]
I want to aggregate count for these dates so total count will be like...
{"hr1":2,
"hr2":35,
"hr3":16,//......so on
}
Is it possible in mongodb? I don't have much knowledge of mongo, if someone can guide me with this query will be helpful...
Running the following aggregation pipeline should give you the desired result:
db.collection.aggregate([
{
"$group": {
"_id": null,
"hr1": { "$sum": "$Count.hr1" },
"hr2": { "$sum": "$Count.hr2" },
"hr3": { "$sum": "$Count.hr3" },
"hr4": { "$sum": "$Count.hr4" },
"hr5": { "$sum": "$Count.hr5" }
}
}
])
Specifying an _id value of null will calculate accumulated values for all the input documents as a whole.