Reputation: 193
I have a model of the following schema:
const mongoose = require('mongoose');
const logSchema = new mongoose.Schema({
probability: {
type: Number,
required: false,
},
timestamp: {
type: Date,
required: true,
}
}, {
timestamps: true
});
const Log = mongoose.model('Log', logSchema);
module.exports = Log;
I want to split all documents to 2 groups: those whose probability
value is less than 0.001
and those whose value is greater than 0.001
. Also, in each group, I want to count for each probabilty
value - how many documents has the same value.
So basically if I had the following probabilities data: [0.00001, 0.000003, 0.000025, 0.000003, 0.9, 0.6, 0.6]
, I'd like to get as a result: { less: { 0.00001: 1, 0.000003: 2, 0.000025:1 }, greater: { 0.9: 1, 0.6: 2 }
.
This is my current aggregate
method:
const livenessProbilitiesData = await Log.aggregate([
{
$match: {
timestamp: {
$gte: moment(new Date(startDate)).tz('Asia/Jerusalem').startOf('day').toDate(),
$lte: moment(new Date(endDate)).tz('Asia/Jerusalem').endOf('day').toDate(),
}
}
},
{
$group: {
}
}
]);
Note that I use undeclared variables startDate, endDate
. These are input I get to filter out irrelevant documents (by timestamp).
Upvotes: 0
Views: 60
Reputation: 193
Solved it by myself:
const livenessProbilitiesData = await LivenessLog.aggregate([
{
$match: {
eventName: 'probability',
timestamp: {
$gte: moment(new Date(startDate)).tz('Asia/Jerusalem').startOf('day').toDate(),
$lte: moment(new Date(endDate)).tz('Asia/Jerusalem').endOf('day').toDate(),
}
},
},
{
$group: {
_id: { $trunc: [ '$probability', 4 ] },
count: { $sum: 1 },
},
},
{
$sort: { _id: 1 },
},
{
$project: {
_id: 0,
less: { $lt: ['$_id', 0.001] },
x: '$_id',
y: '$count',
},
},
{
$group: {
_id: '$less',
probabilities: { $push: { x: '$x', y: '$y' } },
},
},
{
$project: {
_id: 0,
probabilities: 1,
},
}
]);
if (livenessProbilitiesData.length === 0) {
return {
less: [],
greater: [],
}
}
return {
less: livenessProbilitiesData[0].probabilities,
greater: livenessProbilitiesData[1].probabilities,
};
Upvotes: 1
Reputation: 15207
This is what I've tried:
The aggregate has 4 stages:
match
: To filter by date (same what you have).group
: To agroup every probability and it count. That is how many times appears every probability'. Here, the result is something like: [ {prob: 0.6, count:2}, {prob:0.9, count:1}, ... ]
.group
to insert in an array 'less' or 'greater'. Here I've used $cond
. So the result here is: {greater:[{prob:0.9, count:1}, ...], less:[{prob:0.00001, count:1}]}
$project
to remove _id
field from result.db.collection.aggregate([
{
"$match": {
"timestamp": {
"$gte": ISODate("2012-10-15T21:26:17Z"),
"$lte": ISODate("2012-10-15T21:26:17Z")
}
}
},
{
"$group": {
"_id": "$probability",
"count": {
"$sum": 1
}
}
},
{
"$group": {
"_id": null,
"less": {
"$push": {
"$cond": {
"if": {
"$lte": [
"$_id",
0.001
]
},
"then": {
"probability": "$_id",
"count": "$count"
},
"else": "$$REMOVE"
}
}
},
"greater": {
"$push": {
"$cond": {
"if": {
"$gte": [
"$_id",
0.001
]
},
"then": {
"probability": "$_id",
"count": "$count"
},
"else": "$$REMOVE"
}
}
}
}
},
{
"$project": {
"_id": 0
}
}
])
It has not the output exactly you want. Instead of
{
less: {
probability: count
}
...
}
Is like:
{
less:{
probability: X.XXX,
count: X
}
}
This is a mongo playground example
Upvotes: 0