MongoDB Aggregation Framework - How To Query For An Average - javascript

How can I rewrite this MongoDB query using the Aggregation Framework to return the average price for the following Model in between the supplied date range:
Model
var PriceSchema = new Schema({
price: {
type: Number,
required: true
},
date: {
type: Date,
required: true
}
};
Query
exports.getPriceAverage = function(req, res, next) {
var start = moment.utc('03-01-2012').startOf('day');
var end = moment.utc('03-01-2012').endOf('month')
// Aggregation Framework Query Here...
Price.find({ date: { $lt: end, $gt: start }}, function(err, priceAverage) {
// Return average price...
});
};

You mention using aggregation, but you're using the find function which would return all results to the client.
Instead, you need to use aggregate with $avg:
Price.aggregate([
{ $match: { date: { $lt: end, $gt: start } } },
{ $group: { _id: null, avgPrice: { $avg: '$price' } } }
], function(err, results){
// process the results (an array of JavaScript objects)
});

Related

trying to calc average with $avg and got: arguments must be aggregate pipeline operators

got this error: arguments must be aggregate pipeline operators
this is the course 'Schema" that got bootcamp as objectId.
const CourseSchema = new mongoose.Schema({
bootcamp: {
type: mongoose.Schema.ObjectId,
ref: 'Bootcamp',
required: true
}
});
the aggregation :
//static method to get avg of course tuitions
CourseSchema.statics.getAverageCost = async function (bootcampId) {
console.log('calculating avg cost... with bootcampId:' + bootcampId);
const obj = await this.aggragate([{
$match: { bootcamp: bootcampId },
$group: {
_id: '$bootcamp',
averageCost: { $avg: '$tuition' }
}
}]);
console.log(obj);
}
calling for the aggregation before saving or removing:
...
// Call getAvarageCost after save
CourseSchema.post('save', function () {
this.constructor.getAverageCost(this.bootcamp);
})
// Call getAvarageCost before remove
CourseSchema.post('remove', function () {
this.constructor.getAverageCost(this.bootcamp);
})
...
$match and $group must be in different pipeline operations
const cursor = this.aggregate([
{ $match: { bootcamp: bootcampId } },
{
$group: {
_id: '$bootcamp',
averageCost: { $avg: '$tuition' },
},
},
])
console.log(await cursor.toArray())

Limit in mongoose for one query

My schema:
export const MessagesAllSchema = new Schema({
senderName: {type: String, required: true},
senderId: {type: String, required: true},
content: String,
date: {type: Date, default: Date.now()},
roomId: Schema.Types.ObjectId,
});
My query:
AllMessages.find(
{roomId: [roomId1, roomId2]},
(err, messages) => {
console.log(messages);
},
).sort({date: -1});
My code return
My code returns several messages from room 1 and room 2.
I want to achieve
I want to my code return one message for room 1 and one message for room 2. If I apply .limi(2) I got a 2 message for room 1, but I want to get one message per room.
It is not possible with find(), You can try aggregate() method,
$match roomId in array of roomIds
$group by roomId and get first message form multiple grouped messages in root variable
$replceWith to replace root object in root
$sort by date in descending order
$limit 2 documents only
const messages = await AllMessages.aggregate([
{
$match: {
roomId: { $in: [roomId1, roomId2] }
}
},
{
$group: {
_id: "$roomId",
root: { $first: "$$ROOT" }
}
},
{ $replaceWith: "$root" },
{ $sort: { date: -1 } },
{ $limit: 2 }
]).exec();
console.log(messages);
Playground

Mongoose like SQL Distinct with latest date

I try to find all data in my collection with mongoose but I have some problems to understand.
Now I use
const mongoose = require('mongoose');
const CaseSchema = new mongoose.Schema({
szenario: {
type: String,
default: 'deprecated'
},
name: {
type: String,
default: 'test'
},
date: {
type: Date,
default: Date.now
}
});
const Case = mongoose.model('tests', CaseSchema);
module.exports = Case;
May idea of the call is:
Case.find().distinct(name).exec();
But how I can select it distinct for the newest date with mongoose?
To get distinct name with lastest date, you need perform MongoDB aggregation with $group operator:
Case.aggregate([
{
$sort: {
name: 1,
date: 1
}
},
{
$group: {
_id: "$name",
data: {
$last: {
date: "$date",
_id: "$_id"
}
}
}
},
{
$project: {
_id: "$data._id",
date: "$data.date",
name: "$_id"
}
}
]).exec((err, cases) => {
if (err) throw err;
console.log(cases);
});
MongoPlayground

Aggregate by using createdAt with Parse server does not work

I am trying to make aggregation with a Parse server (back4app, Parse server v2.7.1) but while I am able to aggregate by using the fields I explicitly created in the mongoDb, I am unable to aggregate by using the fields 'createdAt' or 'updatedAt'.
As an example, if I invoke:
query.aggregate(pipeline)
With:
{
project: {
objectId: "$objectId",
instr: "$instructions"
}
};
I have an array of records like:
{instr: "1", objectId: "CNHAdpMD0U"}
If on the other side I use:
{
project: {
objectId: "$objectId",
date: "$createdAt"
}
};
I have just:
{objectId: "CNHAdpMD0U"}
Finally, the pipeline:
{
project: {
objectId: "$objectId",
dayOfYear: { $dayOfYear: "$createdAt" }
}
};
Gives "500 - internal server error", but I guess is due to the missing retrieval of "$createdAt".
it seems there is a fix on Parse Server about this. At the moment, you can use like example the cloud function below:
Parse.Cloud.define('yourFunctionName', (req, res) => {
var pipeline = [{
group: {
objectId: { day: { $dayOfMonth: "$_created_at" }, month: { $month: "$_created_at" }, year: { $year: "$_created_at" } },
count: { $sum: 1 } }
}
];
var query = new Parse.Query(Parse.User);
query.aggregate(pipeline, { useMasterKey: true })
.then(function(results) {
res.success(results);
})
.catch(function(error) {
res.error(error)
});
});

How do I average time between to dates in Mongoose js?

I'm trying to query my mLab database and get the average time between two dates. I'm matching the data by name and between two dates (trying to get data within a day). There is data in the DB that i within the dates I'm providing but I'm getting undefined back. I'm not sure what I'm doing wrong.
var dataSchema = mongoose.Schema({
name: String,
start: Date,
end: Date,
key: String
});
module.exports.GetAverageDataWithinRange = function(name, dates, callback) {
Data.aggregate([{
$match: {
name: name,
start: {
$gte: dates.startDate,
$lt: dates.endDate + 1
}
}
}, {
$group: {
_id: "$name",
average: {
$avg: {
$subtract: [{
$millisecond: "$end"
}, {
$millisecond: "$start"
}]
}
}
}
}], function(err, results) {
if (err) {
console.log(err);
} else {
callback(results);
console.log(results);
}
});
}

Categories