Get distinct days from a collection of dates in MongoDB - javascript

I want to populate a date range picker display with highlighted cells where data exists in my database. I thus need to reduce my collection to an array of dates where records exist e.g.
// collection
[{
timestamp: ISODate("2020-01-28T20:42:00.000Z"),
data: 1,
},{
timestamp: ISODate("2020-01-28T18:42:00.000Z"),
data: 10,
},{
timestamp: ISODate("2020-01-28T15:42:00.000Z"),
data: 100,
},{
timestamp: ISODate("2020-01-25T15:42:00.000Z"),
data: 1000,
},{
timestamp: ISODate("2020-01-17T15:42:00.000Z"),
data: 10000,
}]
reduces to:
['2020-01-28', '2020-01-25', '2020-01-17']
The nature of the data stored in my database means that if any data exists on a given date, lots of data exists on that date. It is therefore slow to query the entire collection for a given date range and then reduce the result.
Is there a fast(er) way to query a collection to return the distinct set of dates on which data exists?

As I know you can only get json format result from mongodb query.
I could get the following result, which can be easily converted to the string array in javascript code:
[
{
"_id": "20200125"
},
{
"_id": "20200117"
},
{
"_id": "20200128"
}
]
I used $dateToString aggregation operator inside $project stage.
db.collection.aggregate([
{
$project: {
_id: 0,
date: {
$dateToString: {
format: "%Y%m%d",
date: "$timestamp"
}
}
}
},
{
$group: {
_id: "$date"
}
}
])
Playground

Related

retrieve object in array with condition mongodb

i have a MONGODB database to places like Restaurant Or Cafe and each place have an Array Of Object with name TABLES and each object has Number of table, and Array of booking Dates and details user can book any table by date and time so i want to check available tables and return the table that not booked in this time that user wants to book..
HERE IS MY SCHEMA FOR TABLES ARRAY
tables: [
{
num: Number,
isBooked: {
type: Boolean,
default: false,
},
bookings: [
{
User: {
type: mongoose.Schema.Types.ObjectId,
ref: "Users",
},
Name: {
type: String,
},
Date: {
type: String,
},
Time: {
type: String,
},
Note: {
type: String,
},
numOfPersons: {
type: Number,
},
},
],
},
],
and if user want to book a table at 20/8/2021 , 4:00PM we should check available table for this user at this time requested, we should check on tables and return available table the we push the booking information into it..
i tried some query but always return the whole place not just available table..
const stringDate = new Date(date).toLocaleDateString();
const placeId = req.body.placeId;
const availableTable = await Places.findOne({
_id: placeId,
"tables[0].bookings": {
$not: {
$elemMatch: { $and: [{ Date: stringDate }, { Time: time }] },
},
},
});
availableTable.isBooked = true;
availableTable.bookings.push({
Name: name,
Time: time,
Date: stringDate,
numOfPersons: parseInt(personsNumber),
Note: note,
User: userId,
});
await availableTable.save()
First of all, for simplicity, you should have a separate collection for tables with the restaurant/cafe id in it. That way you can easily do CRUD operations on tables and it would the best approach to handle it.

Find two latest and oldest documents which containing specific field values

Technologies: Mongoose, NodeJS, MongoDB
Question
The following document will save on the MongoDB cluster every 10 seconds.
{
"_id": "6003fafc04cb3727e40812b2",
"currentRound": 39300,
"current": 4.131929,
"voltage": 245.855,
"power": 956.5797,
"frequency": 50,
"totalPower": 1167.862,
"importPower": 1167.862,
"exportPower": 0,
"powerFactor": 0.998356,
"rssi": -59,
"deviceId": "EC:FA:BC:63:02:C1",
"slaveId": 201,
"timestamp": 1610873596543,
"__v": 0
}
There is two types of slave ids (101, 201) documents saving on the same collection and each slave id is having a specific device id. I want to retrieve the most latest and oldest 101 and 201 containing document by using yesterday's timestamps, starting 0:00 AM to 11:59 PM.
Attempt
I have tried the following solution. but distinct('slaveId') returns only the distinct specific field attribute only.
const latestPGStats = await PGStat
.find({
deviceId: { $in: deviceIds },
timestamp: { $lte: endTimestamp, $gte: startTimestamp }
})
.sort({ timestamp: -1 })
.distinct('slaveId')
.limit(2);
I have seen some peoples suggest using mongo aggregation. but I don't have knowledge about that domain.
You can try aggregate(),
$match your conditions
$facet to separate results, first is latest and second is oldest
$sort by timestamp in descending order
$group by slaveId and get $first document in latest and $last document in oldest
$limit` to get single document
const latestPGStats = await PGStat.aggregate([
{
$match: {
deviceId: { $in: deviceIds },
timestamp: { $lte: endTimestamp, $gte: startTimestamp }
}
},
{ $sort: { timestamp: -1 } },
{
$facet: {
latest: [
{
$group: {
_id: "$slaveId",
root: { $first: "$$ROOT" }
}
},
{ $limit: 1 }
],
oldest: [
{
$group: {
_id: "$slaveId",
root: { $last: "$$ROOT" }
}
},
{ $limit: 1 }
]
}
}
])

MongoDB Mongoose group by multiple fields and get the count

I've an analytics API written using MongoDB.
This is my sessions model
const sessionSchema = new Schema(
{
user: { id: Number, name: String, email: String },
},
{ timestamps: true },
);
I want to get the unique users count by the date.
for the date 2019-10-24 there maybe 10 sessions from two users (id 1, id 2)
and
for the date 2019-10-25 there maybe 20 sessions from two users (id 3, id 8)
So my expected results is
2019-10-24 2 users
2019-10-25 2 users
I tried this
db.Session.aggregate([
{
$group: {
_id: { user: '$user.id', day: { $dayOfYear: '$createdAt' } },
count: { $sum: 1 },
},
},
])
and this doesn't seem to work.
My createdAt field's type is Date (eg:- createdAt: 2019-10-16T13:11:17.935Z) That is why I used $dayOfYear: '$createdAt'
db.Session.aggregate([
{
$project: {
date: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } }
}
},
{
$group: {
_id: "$date" ,
count: { $sum: 1 }
}
}
]);
At first group according to createdAt, as we want final result according to createdAt.
In this $group stage just push the userIds into the array, use $addToSet to keep it unique.
Then get the count of userIds with $size operator in $project stage.
You get the result.
Here is the query.
(convert the date as you want, its just a format, and you have done this, so I am skipping this task).
db.sessions.aggregate({$match:{}},
{$group:{_id: "$createdAt", userId : {$addToSet: "$user.id"}}},
{$project:{_id: 1, noOfUsers:{$size:"$userId"}}}).pretty()
Hope this helps!

Is this possible to extract an Object from nested array through mongoDB Query?

I have the following schema in mongoose.
var AttendanceSchema = new mongoose.Schema({
ownerId: mongoose.Schema.Types.ObjectId,
companyId: mongoose.Schema.Types.ObjectId,
months: [
{
currentSalary: {
type: Number,
default: 0
},
month: {
type: Date,
},
salary: {
type: Number,
default: 0
}
days: [
{
manuallyUpdated: {
type: Boolean,
default: false
},
date: {
type: Date,
},
perDaySalary: {
type: Number,
default: 0
},
status: {
type: String,
}
}
]
}
]
});
I want to extract the the single object in days array.
Note: There is days array nested in months array and i have used $pull to pull out that day but i want to pull and push again (updated day).
i think you can do this if you know at which element inside days array there is information you need because days array will consist of multiple elements.
suppose that you need it from 1st element inside array:
Attendance.findOne({_id: request.id}, function(err, foundAttendance){
console.log(foundAttendance.days[0].date);
}
and you can change 0 to any number you want according to data you need.

How to keep null values at the end of sorting in Mongoose? [duplicate]

This question already has answers here:
How can I sort into that nulls are last ordered in mongodb?
(2 answers)
Closed 4 years ago.
I am querying a collection and sorting results based on a property. Some documents don't the that property value yet i.e. null. I want to keep the documents with null values at the end of the results after sorting and limiting (asc or desc). Is there a simple way in Mongoose to do that using a single query?
If not, how can I use two queries separately since I have to limit the results as well for pagination?
var dealSchema = new Schema({
// For Presentation Purposes Only
dealId: { type: Number, index: true, unique: true },
// BRAND Info
brand: { type: ObjectId, ref: 'brand', index: true },
brandUser: { type: ObjectId, ref: 'user', index: true, required: true },
campaign: { type: ObjectId, ref: 'campaign', index: true },
metrics: {
totalCost: Number,
totalValue: Number,
roi: { type: Number, index: true },
cpe: { type: Number, index: true }
}
})
I want to sort based on 'metrics.cpe' in ascending order, but want null or 0 values to be at the end of the list. Example:
[0.1, 0.4, 0.7, 1.5, 2.5, 0, 0, null, null]
Sample document
{
"_id": "590cdf29c102ae31208fa43a",
"campaign": "587e6a880c844c6c2ea01563",
"brand": "5a4cff5f8eaa1c26ca194acc",
"brandUser": "57fd30cf0df04f1100153e07",
"metrics": {
"roi": 0,
"cpe": 0,
"totalValue": 0,
"totalCost": 6000
}
}
Am not sure about the solution am about to say. I cant test this out as I dont have a mongo db set right now, but I think that you can use <collection>.aggregate along with $project and $sort to achieve this.
Sample code:
db.inventory.aggregate(
[
{
$project: {
item: 1,
description: { $ifNull: [ "$amount", -1*(<mimimum value>)* ] }
}
},
{
$sort : {
amount : (-1 or 1 depending on the order you want)
}
}
]
)
Hope this helps !!

Categories