Aggregate to result in current year monthly profit array - javascript

Pretty self-explanatory.
I searched multiple mongo aggregation documentation documents, and built the query the best I could.
Worth to point out I have almost none aggregation experience, and this is onde of the most complex aggregates I have done so far.
let currentYear = new Date();
currentYear.setFullYear(currentYear.getFullYear());
currentYear.setMonth(0);
currentYear.setDate(1);
await Order.aggregate([
{ $match: {
order_ordered_on:{
$gte: currentYear
},
order_status: 'Delivered'
}},
{ $group : {
_id: {month: {$month : '$order_ordered_on'}},
total: {$sum: '$order_total'},
}},
{ $sort : {
_id : 1
}},
{$project: {
_id:1,
total: 1
}}
]).exec((err, result) =>{
if (err) throw err;
let amount = result.map(a => a.total);
res.json({
amount
});
})
To explain my thought process, First I set a date for current year, january first until current time.
Then I match it with the order_ordered_on which has the date which Im working of, and the also match to select only the orders which have the Delivered status.
I group by _id to divide it in months and sum the total amount by months aswell.
Sort it in ascending order do order the array and project the resulting data.
After that I map the result to an array, which is my goal(each position in the array corresponds to a months profit).
The problem is that the total value being returned is absurd and it doesnt match what is expected. Since I dont have much experience, I could not find where Im making the aggregation mistake.
Any help is appreciated.
To make myself clearer, Im currently using a single Order model, and the order_ordered_on, order_status and order_total fields.
The main goal of this aggregate is to split the current year profit in monthly profits, from january 1st until now, and then plot it in a graph through front-end development. The data contains Orders from 2017 until current day. The format the front-end needs to receive is that of an ordered array with the profit values.

Related

How to obtain data from mongoose collection according to week month or years? P.S every document is stored or updated as a single document for a day

I have to show a chart in frontend which takes an array of numbers (7 for a week, 12 for months and 5 for years as shown as shown in the image).
In backend I had a document for everyday which stores and updates on daily basis as unique for a day storing total energy delivered.
Currently I have timestamps in epoch time but I can change it to anything which fulfils my needs.
I want to write queries for obtaining data based on selection using bPID. Suppose I select week it queries last 7 document for a particular bPID and return it to me so that I can filter it out. Suppose I select months so it returns me 31 collections for Jan and 28 for Feb which I would process it in my backend and get an array of 12 for a month. How to query this so that in the end I end up getting array of 7 documents for a week, 12 for a month, 5 for a year.
My current collection:
const analyticSchema = new Schema(
{
bPID: String, // unique for every document
todaysTimeStamp: Number, // epoch time for 12:00 am
energyConsumed: Number
},
{
timestamps: true
}
);
You can get last 7 document for a week, for months you have to query based on this month and get last 365/366 documents. Filter it out based on months. For years you have to get it as mentioned above.

Firestore query: Order by count after a certain date

Supposing a collection of a large number of documents like this:
{
createdAt: 1630789008561, // timestamp
count: 5
},
{
createdAt: 1630788666511, // timestamp
count: 50
},
...
I would like to query the 50 documents with the highest count that were created after a certain timestamp.
One simple solution is to query all documents after this certain timestamp and then order them yourself. But I can't since my database is too large.
My first query attempt was:
db.collection("docs")
.where("createdAt", ">", timestamp)
.orderBy("count", "desc")
.limit(50)
.get();
This query does not work in Firestore and throws:
Error: 3 INVALID_ARGUMENT: inequality filter property and first sort order must be the same: createdAt and count`
I then tried:
db.collection("docs")
.where("createdAt", ">", timestamp)
.orderBy("createdAt", "desc")
.orderBy("count", "desc")
.limit(50)
.get()
This query will not work for me since what it does is taking 50 documents after the timestamp and then order these by count in case they have the same timestamp, which is not what I want.
Edit on why this query does not work:
If I have 150 documents:
50 created on day 1 with a count of 1
50 created on day 2 with a count of 2
50 created on day 3 with a count of 1
If I use this query with a timestamp of 0, I would get back the 50 documents last created (because I am using .orderBy("createdAt", "desc")) which have a count of 1 and are obviously not the ones with the highest count.
If you use asc instead, you get the first documents, which still have not the highest count.
I would like a query that for a timestamp of 0 would give me the 50 documents with the count of 2.
How can I achieve what I want?
EDIT on solution I am currently using (which I'd like to change):
Since my time range is a day, I add a day field in every documents like this:
{
day: '2021-09-06',
createdAt: 1630789008561, // timestamp
count: 5
},
{
day: '2021-09-05',
createdAt: 1630788666511, // timestamp
count: 50
},
...
I can then do an equality check like this:
db
.collection("docs")
.where("day", "==", '2021-09-05')
.orderBy("count", "desc")
.limit(50)
.get();
This works but this is not great since everytime my time range changes I need to update my db schema and update every documents with the new field.
Return the first 50 docs sorted by count. Then you filter by timestamp on the device.
QuerySnapshot<Map<String, dynamic>> query = await db
.collection("docs")
.orderBy("count", "desc")
.limit(50)
.get();
List docs = query.docs.map((e) => e.data()).toList();
// then filter by timestamp on the device
docs.removeWhere((element) => element['createdAt'] < timestamp);
This cannot be done by using where query because there is no way around this limitation.
If you include a filter with a range comparison (<, <=, >, >=), your first ordering must be on the same field:
this is the right query.
db.collection("docs")
.where("createdAt", ">", timestamp)
.orderBy("createdAt", "desc")
.orderBy("count", "desc")
.limit(50)
.get()
But you need to set Firestore Composite Indexes.

how to check date that has no activity for past 10days in Sequelize?

in the database I have a column called,
edited date. I need to write a query.
where: {
lastEditedDateTime:!moment().subtract(10, 'days').toDate()
}
I need to write query that finds the last edited date is greater than 10 days.
I think this is what you're looking for.
where: {
lastEditedDateTime: {
[Op.lte]: moment().subtract(10, 'days').toISOString()
}
}
Here are the search operators in Sequelize: https://sequelizedocs.fullstackacademy.com/search-operators/.

NodeJS MongoDB Find posts that are older than current date

So I have this code line here:
let advertisements = await Advertisement.find({created_at: {$lt: moment().valueOf()}});
This is what it does:
created_at: returns a timestamp when post was created at: 1551198203488.0
moment.valueOf() return me a current timestamp for example: 1551198203488.0
Now I need to write this code line that it only finds ads that are 1 hour old. Is is possible somehow ?
Also I storing and group2_date which store current timestamp BUT with 1 hour added to it like this: moment().add(1, 'h')
You can subtract one hour from the moment using .subtract function and then use $gte operator to obtain only the greater values/documents from the subtracted hours and less then from the current time.
let advertisements = await Advertisement.find({
"created_at": {
"$lte": moment().toDate(),
"$gte": moment().subtract(1, 'hours').toDate()
}
})

Mongoose Query Builder .or not returning expected results

Context
I'm building a query where a user can enter a range of dates to search for 'Player' documents. The query should return any players whose start and end dates overlap with the queried dates. I'm doing this by using an OR condition where either the player's end date is after the query's start date or the player's start date is before the query's end date. Both dates in the query are optional, allowing the user to specify only an end date or a start date, or neither to return all relevant documents.
Problem
The query works when only one of the two query dates are specified (see screenshots below). However, it returns all documents if both dates are specified (functionally ignoring both query parameters).
Code
let query = Player.find({'casino': user.casino});
let queryArray = [];
if(req.body.startDate) {
queryArray.push({playerEndDtm: {$gt: moment(req.body.startDate).toDate()}});
}
if(req.body.endDate) {
queryArray.push({playerStartDtm: {$lt: moment(req.body.endDate).endOf('day').toDate()}});
}
if(queryArray.length > 0) {
query.or(queryArray);
}
Screenshots
When both query dates are specified:
Results:
When only 1 query date is specified:
Results:
Can anyone help me determine what I'm doing wrong? Thanks!
if(req.body.endDate) {
queryArray.push({playerStartDtm: {$lt:
moment(req.body.endDate).endOf('day').toDate()}});
}
In the above query you are justing checking less then the end date. You need to check range between dates:
({ playerStartDtm : { $gt : expression, $lt : expression}})

Categories

Resources