I have created a GET api for results, with filters, pagination and sorting. But though the data is correct, the sorting is not happening correctly.
let skip = 0, limit = 10, findCond = {centerId: self.centersModel.getObjectId(userData.id)};
if(queryParams.result) findCond['result'] = {"$regex": queryParams.result, "$options": 'i'};
if(queryParams.fromDate) findCond['created_at'] = {$gte: moment(queryParams.fromDate + ' 00:00:00', 'DD-MM-YYYY HH:mm:ss').toDate()};
if(queryParams.toDate) {
if(findCond.hasOwnProperty('created_at')) findCond['created_at']['$lte'] = moment(queryParams.toDate + ' 23:59:59', 'DD-MM-YYYY HH:mm:ss').toDate();
else findCond['created_at'] = {$lte: moment(queryParams.toDate + ' 23:59:59', 'DD-MM-YYYY HH:mm:ss').toDate()};
}
if(queryParams.perPage) limit = parseInt(queryParams.perPage);
if(queryParams.page) skip = (parseInt(queryParams.page) - 1) * limit;
let aggregate = [
{ "$match": findCond },
{ "$sort": {"created_at": 1} },
{ "$skip": skip },
{ "$limit": limit }
];
console.log(aggregate)
self.resultsModel.aggregate(aggregate, function(err, results) {
console.log(err, results);
});
Result:
{
"status": "ok",
"results": [
{
"id": "5db83e69fcee977a20b24260",
"result": "Pass",
"examDate": "29/10/2019 06:58 PM"
},
{
"id": "5db6b4d33ffd7d3ccde175d1",
"result": "Pass",
"examDate": "28/10/2019 08:38 PM"
},
{
"id": "5db83e9bfcee977a20b24262",
"result": "Pass",
"examDate": "29/10/2019 06:58 PM"
},
{
"id": "5db83ecafcee977a20b24264",
"result": "Pass",
"examDate": "29/10/2019 06:59 PM"
},
{
"id": "5db83f40fcee977a20b24266",
"result": "Fail",
"examDate": "29/10/2019 07:01 PM"
},
{
"id": "5db84395bb402b0f3de43ff7",
"result": "Pass",
"examDate": "29/10/2019 07:20 PM"
},
{
"id": "5db843c0bb402b0f3de43ff9",
"result": "Pass",
"examDate": "29/10/2019 07:20 PM"
}
]
}
One of the date is 28/10/2019 in between 29/10. Please tell me a reason or a solution to this.
I think, to reduce confusion, you should share the value of aggregate variable that you have logged, rather than the response you create after applying a transformation to it.
Related
I am new to MongoDB. I am having trouble writing filter logic for the following. Would you be so kind to help me out. =>
If isNightParty:true, check in DB for isNightParty Allowed:true and return all documents else Do Not Check
Here is my code:
router.get("/hotelList", (req,res) =>{
const {date, boys, girls, isNightParty} = req.body
businessUser.find(
{
$and:[
{isBlockedOn:{$ne:date}},
//{girlsWithBoys:isGirlsWithBoys},
{"isNightPartyAllowed":{$exists:true}}
}
).then((toListHotels)=>{
return (res.status(200).json(toListHotels))
})
.catch((err)=>{
console.log(err)
})
})
My DB structure is as follows:
{
"_id": {
"$oid": "6182603cce3b3b92991fee96"
},
"hotelName": "Hotel",
"email": "hotel1#hotel.com",
"password": "$2a$12$RXr2xTbnGP2ASUTqP2ptQOtS36QOr0.uq/OHTuIRLigYUM..T3lb6",
"location": "url",
"address": "address",
"isNightPartyAllowed": true,
"girlsWithBoys": true,
"roomSmallData": {
"smallPrice": "1000",
"smallPic": "url",
"smallCapacity": {
"$numberInt": "5"
},
"_id": {
"$oid": "6182603cce3b3b92991fee97"
}
},
"roomMediumData": {
"mediumPrice": "2000",
"mediumPic": "url",
"mediumCapacity": {
"$numberInt": "7"
},
"_id": {
"$oid": "6182603cce3b3b92991fee98"
}
},
"roomLargeData": {
"largePrice": "3000",
"largePic": "url",
"largeCapacity": {
"$numberInt": "10"
},
"_id": {
"$oid": "6182603cce3b3b92991fee99"
}
},
"__v": {
"$numberInt": "0"
},
"isBlockedOn": [
"Fri Nov 05 2021 00:00:00 GMT+0530 (India Standard Time)"
]
}
Use a $or to cater the 2 conditions:
input isNightParty is null
isNightPartyAllowed is true
either case should allow the documents to be returned
db.collection.aggregate([
{
$match: {
$expr: {
$or: [
// put your parameter <isNightParty> here
{
$eq: [
null,
<isNightParty>
]
},
{
$eq: [
{
"$ifNull": [
"$isNightPartyAllowed",
false
]
},
true
]
}
]
}
}
}
])
Here is the Mongo playground for your reference.
I have three fields, id, date and qty in my DB. I want to group them by the id and find the qty which is the latest quantity of every month. So for every month, the date with the latest day of every month, the qty will be returned for it.
If the input is
[
{
"id": "ABC",
"date": "2020-10-02 15:03:00.00",
"qty": 500,
},
{
"id": "ABC",
"date": "2020-10-31 20:22:00.00",
"qty": 100,
},
{
"id": "ABC",
"date": "2020-11-03 04:22:00.00",
"qty": 200,
},
{
"id": "ABC",
"date": "2020-11-18 04:22:00.00",
"qty": 50,
},
{
"id": "ABC1",
"date": "2020-11-05 04:22:00.00",
"qty": 5000,
},
{
"id": "ABC1",
"date": "2020-11-15 04:22:00.00",
"qty": 4580,
},
]
then the output should be
[
{
"id": "ABC",
"qtys": [
{
"date": "2020-10-31 20:22:00.00",
"qty": 100
},
{
"date": "2020-11-18 04:22:00.00",
"qty": 50
}
]
},
{
"id": "ABC1",
"qtys": [
{
"date": "2020-11-15 04:22:00.00",
"qty": 4580
}
]
},
]
$addFields to convert date field from string type to date type, if its already date type then ignore this stage
$sort by date in descending order
$group by id, month and year after extracting from date field
using $year and $month to get first document
$group by only id and construct array of quantities in qtys
db.collection.aggregate([
{ $addFields: { date: { $toDate: "$date" } } },
{ $sort: { date: -1 } },
{
$group: {
_id: {
id: "$id",
month: { $month: "$date" },
year: { $year: "$date" }
},
qtys: { $first: { date: "$date", qty: "$qty" } }
}
},
{
$group: {
_id: "$_id.id",
qtys: { $push: "$qtys" }
}
}
])
Playground
I have a collection in a MongoDB and I would like to get the average of the value in 24 hour time intervals for a given day.
Here is my collection:
[
{
"_id": 1,
"value": 50,
"created_at": 1614217700
},
{
"_id": 2,
"value": 60,
"created_at": 1614219300
},
{
"_id": 3,
"value": 100,
"created_at": 1614226200
},
{
"_id": 4,
"value": 80,
"created_at": 1614227400
}
]
The documents 3 & 4 are in the same hour slot, so the average of 80 and 100 is 90.
Here is an example of what I expect as a result (or something similar).
[
{
"time": 0,
"avg_value": null
},
{
"time": 1,
"avg_value": 50
},
{
"time": 2,
"avg_value": 60
},
{
"time": 3,
"avg_value": null
},
{
"time": 4,
"avg_value": 90
},
,
,
,
{
"time": 23,
"avg_value": null
}
]
Here you can find my example: https://mongoplayground.net/p/YaAeebapbD-
Any ideas will be greatly appreciated.
Thank you!
It is possible for available hours in database, for null values you need to prepare static array and merge with result,
$multiply created_at with 1000 to convert it to milliseconds
$toDate to convert millisecnod to ISO date
$hour to get hour form ISO date
$group by hour that is above converted and average value using $avg
let result = db.collection.aggregate([
{
"$match": {
"created_at": {
"$gte": 1614211200,
"$lt": 1614297599
}
}
},
{
$group: {
_id: { $hour: { $toDate: { $multiply: ["$created_at", 1000] } } },
avg_value: { $avg: "$value" }
}
}
])
Playground
Result will be,
[
{ "_id": 1, "avg_value": 50 },
{ "_id": 2, "avg_value": 60 },
{ "_id": 4, "avg_value": 90 }
]
Merge empty hours and result in client side, If you are using Javascript / NodeJs you can see example,
// RESULT FROM QUERY
let result = [
{ "_id": 1, "avg_value": 50 },
{ "_id": 2, "avg_value": 60 },
{ "_id": 4, "avg_value": 90 }
];
// GENERATE NULL HOURS FOR 23 HOURS IN ARRAY
let hours = [];
for (let i = 0; i<24; i++) hours.push({ _id: i, avg_value: null });
// MERGE WITH QUERY RESULT
let mergeArray = hours.map(h => {
let f = result.find(r => h._id === r._id);
return f ? f : h;
});
console.log(mergeArray);
Hi I have been trying since last two days to find all post that satisfy all the criteria for current date, but still haven't figured out the right way
const today = await Posts.aggregate([
{
$match: {
$expr: {
$and: [
{ chk_featured: true },
{ featured_type: 't' },
{ $eq: [{ $dayOfMonth: '$publish_date' }, { $dayOfMonth: new Date() }] },
],
},
}
}
]);
if (!today) return res.status(404).json({ msg: "no records found" });
return res.status(200).json({ today: today });
{
"_id": "5f8047b5f5af011b642b6bb1",
"sel_interest_group": ["name2,name1"],
"status": "a",
"title": "aweasdasd",
"description": "sadsadsa",
"chk_featured": true,
"sel_age_group": "2",
"publish_date": {
"$date": "2020-09-28T18:30:00.000Z"
},
"slug": "aweasdasd",
"__v": 0,
"featured_type": "n"
},
{
"_id": "5f8047b5f5af011b642b6bb1",
"sel_interest_group": ["name2,name1"],
"status": "a",
"title": "aweasdasd",
"description": "sadsadsa",
"chk_featured": true,
"sel_age_group": "2",
"publish_date": "2020-10-28T18:30:00.000Z",
"slug": "aweasdasd",
"__v": 0,
"featured_type": "n"
},
{
"_id": "5f8047b5f5af011b642b6bb1",
"sel_interest_group": ["name2,name1"],
"status": "a",
"title": "aweasdasd",
"description": "sadsadsa",
"chk_featured": true,
"sel_age_group": "2",
"publish_date": "2020-10-23T18:30:00.000Z",
"slug": "aweasdasd",
"__v": 0,
"featured_type": "t"
},
{
"_id": "5f8047b5f5af011b642b6bb1",
"sel_interest_group": ["name2,name1"],
"status": "a",
"title": "4th post",
"description": "sadsadsa",
"chk_featured": true,
"publish_date": "2020-09-28T18:30:00.000Z"
"slug": "aweasdasd",
"__v": 0,
"featured_type": "n"
}
Unable to figure it out what is wrong in this ,as I am a first time user in Mongodb
Any help is appreciated.
If I'm correct, this line from the docs
{ $and: [ <expression1>, <expression2>, ... ] }
implies that you can't have a plain object inside, like this:
{ chk_featured: true }
but only expressions.
So I tweaked it this way:
db.test.aggregate([{
$match: { $expr: {$and: [
{ $eq:["$chk_featured", true] },
{ $eq:["$featured_type", 't'] },
{ $eq: [{ $dayOfMonth: '$publish_date' }, { $dayOfMonth: new Date() }] }
]}}
}]);
Edit
This other expression could be easier to read. (Didn't test).
db.test.find({
"chk_featured":true,
"featured_type":"t",
{"$expr": { $eq: [
{ $dayOfMonth: '$publish_date' },
{ $dayOfMonth: new Date() }
] } }
})
I have three documents:
{
"id_user": "t57092501745ad6285ac58c22",
"name": "Day #1",
"date": {
"$date": "2016-04-21T20:50:00.190Z"
},
"text": "My text"
}
{
"id_user": "t57092501745ad6285ac58c22",
"name": "Day #2",
"date": {
"$date": "2016-04-22T20:50:00.190Z"
},
"text": "My text"
}
{
"id_user": "t57092501745ad6285ac58c22",
"name": "Day #3",
"date": {
"$date": "2016-04-22T20:51:00.190Z"
},
"text": "My text"
}
and I need to group these for day, so I do:
{
"$match": {
"id_user": "t57092501745ad6285ac58c22"
}
}, {
"$sort": {
"date": -1
}
}, {
"$group": {
"_id": {
$dayOfYear: "$date"
},
"data": {
"$push": {
"id_user": "$id_user",
"name": "$name",
"date": "$date",
"text": "$text"
},
},
}
}
and the result is:
{
{
_id: 113,
data: [{
"id_user": "t57092501745ad6285ac58c22",
name: "Day #1",
date: "2016-04-22T20:51:00.190Z",
text: "My text"
}]
}, {
_id: 114,
data: [{
"id_user": "t57092501745ad6285ac58c22",
name: "Day #3",
date: "2016-04-23T20:51:00.190Z",
text: "My text"
}, {
"id_user": "t57092501745ad6285ac58c22",
name: "Day #2",
date: "2016-04-23T20:50:00.190Z",
text: "My text"
}]
}
}
and it's ok, but the order is not what I need:
{ Day #1 }, { Day #3, Day #2 }
if I change the sort to { "date": 1 } I can invert the order of the 2 groups, this way:
{ Day #3, Day #2 }, { Day #1 }
but I don't know how tho change also the order inside the sub-array, to obtain the correct:
{ Day #1 }, { Day #2, Day #3 }
What's the correct way?
If you want the items in the "array" to be in "ascending" order, then your $sort order is wrong, and you need to reverse it. Also output from $group as a "document" is not ordered in any way. So if you want a specific order then you need to actually $sort on the returned _id as well:
[
{ "$match": {
"id_user": "t57092501745ad6285ac58c22"
}},
{ "$sort": { "date": 1 } }
{ "$group": {
"_id": { "$dayOfYear": "$date" },
"data": {
"$push": {
"id_user": "$id_user",
"name": "$name",
"date": "$date",
"text": "$text"
}
}
}},
{ "$sort": { "_id": 1 } }
]
Then both orders are then correct