Mongoose: $sum if conditions - javascript

I have a query with find and aggregate that find in Schedule model, and calculate the sum of total of services and the sum of total value of services. But I need to make this sum (sum of totalServices) with a condition, where the ´status´ equal to 2. can i make this?
My query:
Schedule.find(findTerm)
.skip(req.body.page * req.body.limit)
.limit(Number(req.body.limit))
.select(
"service.name value scheduleStart scheduleEnd comissionValue status paymentMethod"
)
.exec((err, response) => {
if (err) res.status(500).send(err);
Schedule.find(findTerm)
.count()
.exec((error, count) => {
if (error)
res.status(500).send({
error,
code: 0,
message: "Erro."
});
Schedule.aggregate([{
$match: {
store: req.body.store,
}
},
{
$group: {
_id: {
id: "$store"
},
totalValue: {
$sum: "$value"
},
totalServices: {
$sum: {
$cond: [ {
$eq: [ "$status", 2 ]
}]
}
},
count: {
$sum: 1
}
}
}...
Result of my query:
...{
"service": {
"name": "CABELO + BARBA"
},
"comissionValue": 0,
"paymentMethod": 0,
"_id": "5bfec336c6f00d2e88f8d765",
"scheduleStart": "2018-11-28 14:35",
"scheduleEnd": "2018-11-28 15:45",
"status": 2,
"value": 75
},
{
"service": {
"name": "Barba"
},
"comissionValue": 0,
"paymentMethod": 0,
"_id": "5bfec3ffc6f00d2e88f8d766",
"scheduleStart": "2018-11-28 18:30",
"scheduleEnd": "2018-11-28 18:50",
"status": 2,
"value": 20
}
],
"count": 4299,
"group": [
{
"_id": {
"id": "5b16cceb56a44e2f6cd0324b"
},
"totalValue": 777780048281, //right value
"totalServices": 945, //wrong value
"count": 676
}
]
}
I need to filter the sum of totalServices to only objects if the status equal to 2 (I tried to use $cond but not worked).

You need to check the status conditionally($cond) i.e. if status is equal ($eq) to 2 then $sum the value field else pass 0
Schedule.aggregate([
{ "$match": { "store": req.body.store }},
{ "$group": {
"_id": { "id": "$store" },
"totalValue": { "$sum": "$value" },
"totalServices": {
"$sum": { "$cond": [{ "$eq": ["$status", 2] }, 1, 0] }
},
"count": { "$sum": 1 }
}}
])

Related

Mongoose: Get objects by a search query

I am trying to pull out data of 2 types from my BSON document using mongoose.
The 2 data are;
Intention 1 - I want to get objects from the items array where tagNo == 2
Intention 2 -I want to get objects from the items array where tagNo == 2 and tagID == kLawOURVpz1IIjoQ2fhCvy7NM.
For intention 1, I tried;
db.find(
{ "fileID": "0pdn3jdndndj3msms, "items.tagNo": 2 },
{
"items": {
"$elemMatch": { "tagNo": 2 }
}
}
);
and I tired the query below for intention 2
db.find(
{ "fileID": "0pdn3jdndndj3msms, "items.tagNo": 2 },
{
"items": {
"$elemMatch": { "tagNo": 2, "tagID": "kLawOURVpz1IIjoQ2fhCvy7NM", }
}
}
);
I keep getting the entire object back.
My BSON document is;
{
"_id": "ID_GOES_HERE",
"fileID": "0pdn3jdndndj3msms",
"fileName": "Item List",
"items": [
{
"tagNo": 2,
"status": 0,
"tagID": "kLawOURVpz1IIjoQ2fhCvy7NM",
"tagUnit": 5
},
{
"tagNo": 2,
"status": 0,
"tagID": "kLawOURVpz1IIjoQ2fhCvy7NM",
"tagUnit": 8
},
{
"tagNo": 2,
"status": 0,
"tagID": "pOawOURVpz1IIjoQ2fhCvy7w3",
"tagUnit": 81
},
{
"tagNo": 4,
"status": 0,
"tagID": "kLawOURVpz1IIjoQ2fhCvy7NM",
"tagUnit": 904
},
{
"tagNo": 3,
"status": 0,
"tagID": "pOawOURVpz1IIjoQ2fhCvy7w3",
"tagUnit": 24
},
{
"tagNo": 2,
"status": 0,
"tagID": "pOawOURVpz1IIjoQ2fhCvy7w3",
"tagUnit": 35
},
{
"tagNo": 1,
"status": 0,
"tagID": "kLawOURVpz1IIjoQ2fhCvy7NM",
"tagUnit": 11
},
{
"tagNo": 2,
"status": 0,
"tagID": "kLawOURVpz1IIjoQ2fhCvy7NM",
"tagUnit": 30
}
]
}
You need aggregation framework
db.collection.aggregate([
{
$match: { //Match condition to get the matching arrays
"fileID": "0pdn3jdndndj3msms",
"items.tagNo": 2
}
},
{
$project: {
"items": {
$filter: { //Project only matching array elements
input: "$items",
as: "item",
cond: {
$eq: [
"$$item.tagNo",
2
]
}
}
}
}
}
])
Playground
db.collection.aggregate([
{
$match: {
"items": {
"$elemMatch": {
"tagNo": 2,
"tagID": "kLawOURVpz1IIjoQ2fhCvy7NM",
}
}
}
},
{
$project: {
"items": {
$filter: {
input: "$items",
as: "item",
cond: {
"$and": [
{
$eq: [
"$$item.tagNo",
2
]
},
{
$eq: [
"$$item.tagID",
"kLawOURVpz1IIjoQ2fhCvy7NM"
]
}
]
}
}
}
}
}
])
Playground

Find user is registered to a Event in MongoDb (aggregation)

I tried to find users who are registered for that event.
So I join multiple collections shown below -
Events.aggregate([
{ $match: { category: "group_event" } },
// collection where events are scheduled
{
$lookup: {
from: "group_events",
let: { eventId: "$eventID" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ["$_id", "$$eventId"] },
{ $gt: ["$time", new Date()] },
],
},
},
},
// register user collection
{
$lookup: {
from: "register_events",
let: { eventId: "$_id" },
pipeline: [
{ $match: { $expr: { $eq: ["$eventId", "$$eventId"] } } },
],
as: "registerUsers",
},
},
],
as: "events",
},
},
{ $unwind: "$events" },
])
and the output is now comingout -
[
{
"_id": "614d6dfd82cb36be231083c9",
"trainerId": "61488dc36b7ccedbc884d20a",
"category": "group_event",
"eventID": "614d6dfc82cb36be231083c7",
"createdAt": "2021-09-24T06:19:41.268Z",
"updatedAt": "2021-09-24T06:19:41.268Z",
"__v": 0,
"events": {
"_id": "614d6dfc82cb36be231083c7",
"groupName": "group name 4",
"category": "sdfsdf",
"time": "2021-09-27T07:44:58.762Z",
"description": "description",
"day": "sunday",
"platform": "zoom",
"notes": "22",
"skills_to_learn": [
"demo"
],
"status": "pending",
"trainerId": "61488dc36b7ccedbc884d20a",
"meetingLink": "https://us05web.zoom.us/j/81660534858?pwd=cGZaODVjdWJUQWNtN243MlNiVUN0UT09",
"type": "group_event",
**isUserRegisted : true / false,**
"createdAt": "2021-09-24T06:19:41.000Z",
"updatedAt": "2021-09-24T06:19:41.000Z",
"__v": 0,
"registerUsers": [
{
"_id": "614ed6b4b8a545acb8517e85",
"userId": "614d59371d11becb8e23f536",
"eventId": "614d6dfc82cb36be231083c7",
"question": "",
"createdAt": "2021-09-25T07:58:44.939Z",
"updatedAt": "2021-09-25T07:58:44.939Z",
"__v": 0
}
]
}
}
]
which is ok for me bu just wanted to add a key: value, heighlited on obove section
isUserRegisted : true / false
i tried with $addFields but can't came up with any solution. Basically I need to retrieve arrays from registerUsers - collection and on the same time match the userId
I was able to figure out this issue.
simply I need to use $project and $filter to get the data if available and at last use $cond to return true or false
{
$project: {
root: "$$ROOT",
userFound: {
$filter: {
input: "$registerUsers",
as: "ac",
cond: {
$eq: ["$$ac.userId", mongoose.Types.ObjectId(userId)],
},
},
},
},
},
{
$project: {
_id: 0,
document: "$$ROOT",
userFound: {
$cond: {
if: { $isArray: "$userFound" },
then: {
$cond: {
if: {
$gt: [{ $size: "$userFound" }, 0],
},
then: true,
else: false,
},
},
else: false,
},
},
},
},
// merging nested object with parents
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$document.root",
{ isUserRegistered: "$userFound" },
],
},
},
},

How to sum data after remove duplicate ($addToSet) mongoose aggregate

i have struggle to sum value after remove duplicate in mongoose. i have data like this:
{
"_id": "6006c7f624d9e1364051b0aa",
"paidFrom": "5fec1b5d124c58c6ddacfd02",
"amount": 234,
},
{
"_id": "600e63f2545087cbddfe370a",
"paidFrom": "5fec1b5d124c58c6ddacfd02",
"amount": 25000,
},
{
"_id": "600e7c16545087cbddfe370b",
"paidFrom": "5ff56473609e930518cb7b67",
"amount": 5000,
},
i want to remove duplicate data using aggregation, i want to sum by the same paid from value.
this is my code:
const dataAP = await AccountPayment.aggregate([
{
$match: filterDate
},
{
$group: {
_id: null,
paidFrom: {
"$addToSet" : "$paidFrom",
},
amount: {$sum: "$amount"}
}
},
],
function (err, res)
{
if (err) {}
console.log(err)
});
but that code give me result:
"status": "success",
"data": [
{
"_id": null,
"paidFrom": [
"5ff56473609e930518cb7b67",
"5fec1b5d124c58c6ddacfd02",
"5ff54212609e930518cb7b65"
],
"amount": 60234
}
]
}
my expected result is:
"status": "success",
"data": [
{
"_id": null,
"paidFrom": [
"5ff56473609e930518cb7b67",
],
"amount": 20000
},
{
"_id": null,
"paidFrom": [
"5fec1b5d124c58c6ddacfd02",
],
"amount": 20000
},
{
"_id": null,
"paidFrom": [
"5ff54212609e930518cb7b65",
],
"amount": 20234
},
]
}
i want amount is sum by duplicate value, so i can calculate the duplicate value. can someone tell me whats wrong? thanks
You just need to group by paidFrom id and sum amount, it will group duplicate documents and sum total amount
const dataAP = await AccountPayment.aggregate([
{ $match: filterDate },
{
$group: {
_id: "$paidFrom",
amount: { $sum: "$amount" }
}
}
],
function (err, res) {
if (err) console.log(err);
})
Playground

Getting only last field in mongoose $in Operator

I am trying to find all person records that time between start and end and have place id in [1,2] This is my query:
Person.find({
time: {
$gte: start,
$lt: end
},
"place.place_id": { $in: [1,2] }
}, {
"time":1,
"place.$": 1
},
function (err, docs) {
if (err) {
res.status(500).send(err);
} else {
res.status(200).send(docs);
}
}
);
But I am getting only one place. This is my output
[
{
"_id": "5bffc1e9bd35e42020c05cf1",
"time": "2018-11-29T10:38:01.401Z",
"places": [
{
"_id": "5bffc1e9bd35e42020c05de3",
"place_id": 1,
"place_name": "test1"
}
]
},
{
"_id": "5bffc256bd35e42020c05de4",
"time": "2018-11-29T10:40:01.324Z",
"places": [
{
"_id": "5bffc256bd35e42020c05ed6",
"place_id": 1,
"place_name": "test1",
}
]
}
]
I am getting only place which have id 1 my desired output is
[
{
"_id": "5bffc1e9bd35e42020c05cf1",
"time": "2018-11-29T10:38:01.401Z",
"places": [
{
"_id": "5bffc1e9bd35e42020c05de3",
"place_id": 1,
"place_name": "test1"
},
{
"_id": "5bffc1e9bd35e42020c05de3",
"place_id": 2,
"place_name": "test2"
}
]
},
{
"_id": "5bffc256bd35e42020c05de4",
"time": "2018-11-29T10:40:01.324Z",
"places": [
{
"_id": "5bffc256bd35e42020c05ed6",
"place_id": 1,
"place_name": "test1",
},
{
"_id": "5bffc256bd35e42020c05ed6",
"place_id": 2,
"place_name": "test2",
}
]
}
]
Update
Tried this but this gives me empty object
Persons.find({
time: {
$gte: start,
$lt: end
},
places: {
$filter: {
input: "$places",
as: "place",
cond: { $in: ["$$place.place_id",[ 1,2 ]] }
}
}
},
function (err, docs) {
if (err) {
res.status(500).send(err);
} else {
res.status(200).send(docs);
}
}
);
};
What am I doing wrong?? I also tried $elemMatch, $all Operator but same output.
How can I get all these places?
Thanks.
Update2
I am entrying data after every 2 minutes this is start and end values
var end = new Date();
var start = new Date(end);
start.setMinutes(end.getMinutes() - 10);
You need to use aggregation for this. Something like
db.collection.aggregate([
{ "$match": {
"time": { "$gte": start, "$lt": end },
"place.place_id": { "$in": [1, 2] }
}},
{ "$project": {
"time": 1,
"places": {
"$filter": {
"input": "$places",
"as": "place",
"cond": { "$in": ["$$place.place_id", [1, 2]] }
}
}
}}
])

Why the following query does not return any data?

I have a collection in mongodb and indexed on the field name , i do a free search using the following query to get matched results and limit to 5,
db.getCollection('_event').aggregate([
{
"$match": {
"$and": [
{
"$text": {
"$search": "liver"
}
},
{},
{}
]
}
},
{
"$group": {
"_id": null,
"count": {
"$sum": 1
},
"results": {
"$push": "$$ROOT"
}
}
},
{
"$project": {
"count": 1,
"results": {
"$slice": [
"$results",
5
]
}
}
}
])
but there is a data with liverpool . when i do replace it with "$search": "liverpool" it returns data.
what is the issue here?

Categories

Resources