MongoDB: Group by date and other value - mongodb

I have this values on my MongoDB:
I need to group them by date and by the value. I need to create a chart that shows when the value changed. And I need to show only if the value changed.
How can I do it in MongoDb?
My currently aggregation is like this:
let history = await History.aggregate([
{
$match: {
address: "123456",
token_to_index: "1"
}
},
{
$group: {
_id : {
date: "$date",
floor_price: "$stats.floor_price"
},
count: { $sum: 1 }
}
},
{
$sort: { "_id.date": 1}
}
]);
I basically need this on MongoDB:
history = history.filter((item, index) => {
if(index === 0) {
return item;
} else {
if(history[index-1]._id.floor_price !== item._id.floor_price) {
return item;
}
}
})
Thanks!

You can change your query,
$group by floor_price field and get max date by $max
$sort by date in ascending order
let history = await History.aggregate([
{
$match: {
address: "123456",
token_to_index: "1"
}
},
{
$group: {
_id: "$stats.floor_price",
date: { $max: "$date" },
count: { $sum: 1 }
}
},
{ $sort: { "date": 1 } }
])
Playground

Related

mongdb match when some variables is exist, if its not exist , do not match with it

let list = await TDataModel.aggregate([
{
$match: {
device_id,
createdAt: { $gte: startTime, $lte: endTime }
}
},
{
$sort: { createdAt: -1 }
}
])
when the device_id is exist, i want match with it, but when it not exist(it was null), i want match without it. do you have some good suggestion.
now, i am doing with that
let list = []
if (device_id) {
list = await TDataModel.aggregate([
{
$match: {
device_id,
createdAt: { $gte: startTime, $lte: endTime }
}
},
{
$sort: { createdAt: -1 }
}
])
} else {
list = await TDataModel.aggregate([
{
$match: {
createdAt: { $gte: startTime, $lte: endTime }
}
},
{
$sort: { createdAt: -1 }
}
])
}
even it can resolve my problem,but i think there must be a better way
What you're doing is fine, however we can just make it a little sexier via some sugar syntax in the ternary operator
let list = await TDataModel.aggregate([
{
$match: {
$and: [
device_id ? device_id : {},
{
createdAt: { $gte: startTime, $lte: endTime }
}
]
}
},
{
$sort: { createdAt: -1 }
}
])
You can created a variable and store your conditions in it,
created match variable, if device_id not null then add in match variable
let match = { createdAt: { $gte: startTime, $lte: endTime } };
if (device_id) match.device_id = device_id;
let list = await TDataModel.aggregate([
{ $match: match },
{ $sort: { createdAt: -1 } }
])

Sum value when satisfy condition in MongoDB

I am trying to get sum of values when certain condition is satisfied in the document.
In the below query i want to get sum of currentValue only when componentId = "ABC"
db.Pointnext_Activities.aggregate(
{ $project: {
_id: 0,
componentId:1,
currentValue:1
}
},
{ $group:
{ _id: "$componentId",
total: { $sum: "$currentValue" }
}
}
)
Please try this :
db.Pointnext_Activities.aggregate([{ $match: { componentId: 'ABC' } },
{
$group:
{
_id: "$componentId",
total: { $sum: "$currentValue" }
}
}, { $project: { 'componentId': '$_id', total: 1, _id: 0 } }])
If you just need the total value & doesn't care about componentId to be returned try this :
db.Pointnext_Activities.aggregate([{ $match: { componentId: 'ABC' } },
{
$group:
{
_id: "",
total: { $sum: "$currentValue" }
}
}, {$project :{total :1, _id:0}}])
It would be ideal in aggregation, if you always start with filter operation i.e; $match, as it would persist only needed documents for further steps.

how to sum up the document in mongo db

Now I want to query "SUM the number of Score between Q1 to Q5 (the result should be 4). Attached the collection snapshot of mlab.
mlab snapshot
db.temp.aggregate({ $match: {
$and: [
{ QuestionNo: { $gte: 1 } },
{ QuestionNo: { $lte: 5 } }
]
}},
{ $group: { _id : null, sum : { $sum: "$Score" } } });
I dont see any response in console. Any help is much appreciated.
First of all there is no need to over complicate your match query. What you want is basically all QuestionNo's between 1-5. I assume your documents look something like this:
{
"QuestionNo" : 1,
"Score" : 55
}
/* 2 */
{
"QuestionNo" : 2,
"Score" : 33
}
etc...
If you want to sum all the results then you can do
db.temp.aggregate(
{
$match: {
QuestionNo: { $gte: 1 , $lte: 5 }
}
},
{
$group: {
_id: null,
sum: { $sum: "$Score"}
}
}
)
If you want to group them by QuestionNo then you can do this:
db.temp.aggregate(
{
$match: {
QuestionNo: { $gte: 1 , $lte: 5 }
}
},
{
$group: {
_id: "$QuestionNo",
sum: { $sum: "$Score"}
}
}
)

Mongo aggregation query to calculate multiple computed values

Given the below documents.
{
_id: 1,
ExpirationDate: ISODate("2017-05-02T09:29:46.006+0000")
}
{
_id: 2,
ExpirationDate: ISODate("2017-05-12T09:29:46.006+0000")
}
{
_id: 3,
ExpirationDate: ISODate("2017-05-23T09:29:46.006+0000")
}
How can I use aggregation pipleline to compute the following output?
{
"NumberOfSubscriptionExpiringToday": 12,
"NumberOfSubscriptionExpiringWithInAWeek": 4
}
I am looking to accomplish this with just one query instead of two. Here is what I have so far...
.aggregate([
{
$match: {
"ExpirationDate": {
$gte: ISODate("2017-05-02T00:00:00.000+0000"),
$lte: ISODate("2017-05-03T00:00:00.000+0000")
}
}
},
{
$project: {
_id: 1
}
},
{
$count: "ExpiringToday"
}
]);
.aggregate([
{
$match: {
"ExpirationDate": {
$gte: ISODate("2017-05-02T00:00:00.000+0000"),
$lte: ISODate("2017-05-08T00:00:00.000+0000")
}
}
},
{
$project: {
_id: 1
}
},
{
$count: "ExpiringInSevenDays"
}
]);
You can do it in single aggregation query with $cond operator to check if each document expiration date falls into [today, tomorrow) range, or in [tomorrow, weekAfterToday) range:
var today = ISODate("2017-05-04T00:00:00.000");
var tomorrow = ISODate("2017-05-05T00:00:00.000");
var weekAfterToday = ISODate("2017-05-11T00:00:00.000");
db.collection.aggregate([
{ $match: { "ExpirationDate": { $gte: today, $lt: weekAfterToday }}},
{
$project: {
ExpiringToday: {
$cond: {
if: {
$and: [
{$gte: ["$ExpirationDate",today]},
{$lt:["$ExpirationDate",tomorrow]}
]
}, then: 1, else: 0
}
},
ExpiringInAWeek: {
$cond: { if: {$gte: ["$ExpirationDate",tomorrow]}, then: 1, else: 0 }
}
}
},
{ $group: {
_id: 1,
NumberOfSubscriptionExpiringToday: {$sum: "$ExpiringToday" },
NumberOfSubscriptionExpiringWithInAWeek: {$sum: "$ExpiringInAWeek" }
}
},
{ $project: { _id: 0 }}
]);
Consider also to make two simple requests:
var numberOfSubscriptionExpiringToday = db.collection.count(
{ "ExpirationDate": { $gte: today, $lt: tomorrow }}
);
var numberOfSubscriptionExpiringWithInAWeek = db.collection.count(
{ "ExpirationDate": { $gte: tomorrow , $lt: weekAfterToday }}
);

MongoDB Delete records where group by count

I have a lot of records that contains duplicate addresses. Basically, I want to delete those records that has number of duplicate addresses more than 50 but less than 300.
This is how I get those records that I want to delete:
db.directories.aggregate( [
{ $group: { _id: { address: "$address" }, total: { $sum: 1 } } },
{ $match: { total: { $gt: 50, $lt: 300 } } },
{ $sort: { total: -1 } }
], { allowDiskUse: true });
You can use the cursor method forEach() to iterate the cursor returned from the aggregate() method and delete the documents using the remove() method, as in the following example:
var pipeline = [
{ $group: { _id: { address: "$address" }, total: { $sum: 1 } } },
{ $match: { total: { $gt: 50, $lt: 300 } } },
{ $sort: { total: -1 } }
];
var options = { allowDiskUse: true };
db.directories.aggregate(pipeline, options).forEach(function (doc){
var query = {"address": doc._id.address};
db.directories.remove(query);
});