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
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())
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
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
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)
});
});
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);
}
});
}