Mongo DB query to return count? - javascript

I have two collections Course and File.
This is my data from Course collection
[{
_id: 1,
name: "Course1",
price: "100"
},
{
_id: 2,
name: "Course2",
price: "200"
}]
This is my data from files collection
[{
_id: 1,
name: "File1",
isFree: true,
courseId: 1
}
{
_id: 2,
name: "File2",
isFree: false,
courseId: 1
}
{
_id: 3,
name: "File3",
isFree: false,
courseId: 1
}]
I want to retrieve Course 1 with Course name,Count of files which are free,Count of files which are not free.
My attempt:
Course.aggregate([
{$lookup:{
from:"files",
localField: "_id",
foreignField: "courseId",
as: "files"
}},
])
This is my response If I execute my above query:
[
{
"_id": "6161bdcc0aada09d81598840",
"name": "Course1",
"files": [
{
"_id": "6166a0814ad3f56b71232b9c",
"name": "File1.jpeg",
"isFree":true
},
{
"_id": "6166a0814ad3f56b71232b9d",
"name": "File2.jpeg",
"isFree":false
},
{
"_id": "6166a0814ad3f56b71232b9v",
"name": "File3.jpeg",
"isFree":false
}
]
}
]
I want my output as:
[
{
"_id": "6161bdcc0aada09d81598840",
"name": "Course1",
"files": {"free": 1,"paid": 2}
}
]

You can try lookup with pipeline,
$lookup with pipeline, pass courseId in let
$match courseId condition
$group by isFeee and get total count
$project to show required fields in k(key) and v(value) format
$cond to check if isFree true then return "free" otherwise return "paid"
$addFields to update files array
$arrayToObject convert files key-value array to an object
$ifNull to check if property is not exists then set 0
await Course.aggregate([
{
$lookup: {
from: "files",
let: { courseId: "$_id" },
pipeline: [
{ $match: { $expr: { $eq: ["$$courseId", "$courseId"] } } },
{
$group: {
_id: "$isFree",
count: { $sum: 1 }
}
},
{
$project: {
_id: 0,
k: { $cond: ["$_id", "free", "paid"] },
v: "$count"
}
}
],
as: "files"
}
},
{
$addFields: {
files: { $arrayToObject: "$files" }
}
},
{
$addFields: {
"files.free": { $ifNull: ["$files.free", 0] },
"files.paid": { $ifNull: ["$files.paid", 0] }
}
}
])
Playground

Try following:
db.course.aggregate([
{
$lookup: {
from: "files",
localField: "_id",
foreignField: "courseId",
as: "files",
},
},
{
$unwind: {
path: "$files",
preserveNullAndEmptyArrays: true,
},
},
{
$group: {
_id: "$_id",
name: {
$first: "$name",
},
price: {
$first: "$price",
},
free: {
$sum: {
$cond: [
{
$eq: ["$files.isFree", true],
},
1,
0,
],
},
},
paid: {
$sum: {
$cond: [
{
$eq: ["$files.isFree", false],
},
1,
0,
],
},
},
},
},
{
$addFields: {
"files.free": "$free",
"files.paid": "$paid",
},
},
{
$project: {
_id: 1,
name: 1,
files: 1,
price: 1,
},
},
]);

Related

How to group result of lookup aggregate results

I aggregate users document:
User.aggregate([
{
$match: { _id: req.params.id },
},
{
$lookup: {
from: 'moods',
localField: '_id',
foreignField: 'source.userId',
pipeline: [
{
$lookup: {
from: 'contactrequests',
localField: 'source.userId',
foreignField: 'source.userId',
let: {
// truncate timestamp to start of day
moodsDate: {
$dateTrunc: {
date: '$timestamp',
unit: 'day',
},
},
},
pipeline: [
{
$match: {
$expr: {
$eq: [
'$$moodsDate',
{
// truncate timestamp to start of day
$dateTrunc: {
date: '$timestamp',
unit: 'day',
},
},
],
},
},
},
],
as: 'contactRequests',
},
},
],
as: 'calendar',
},
},
]).exec()
There is final document what I get
{
"_id": "P4SpYVd1KjBaF4SKyVw0E",
"lastName": "Doe",
"login": "User-01",
"name": "John"
"calendar": [
{
"_id": "62a351e33859aaf975c63323",
"source": {
"userId": "P4SpYVd1KjBaF4SKyVw0E",
"deviceId": "Pacjent-141214"
},
"timestamp": "2022-06-07T12:44:13.333Z",
"mood": "good",
"contactRequests": []
},
{
"_id": "62a351f43859aaf975c63327",
"source": {
"userId": "P4SpYVd1KjBaF4SKyVw0E",
"deviceId": "Pacjent-141214"
},
"timestamp": "2022-06-09T12:44:13.333Z",
"mood": "middle",
"contactRequests": [
{
"timestamp": "2022-06-09T12:44:13.333Z",
"source": {
"deviceId": "Pacjent-141214",
"userId": "P4SpYVd1KjBaF4SKyVw0E"
},
"resolve": false,
"_id": "62a351ff3859aaf975c63329",
},
]
}
]
},
This is what I would to get. This is more clean and readable.
{
"_id": "P4SpYVd1KjBaF4SKyVw0E",
"login": "User-01",
"name": "John",
"lastName": "Doe",
"calendar": [
{
"timestamp": "2022-06-11T12:44:13.333Z"
"mood": {
"source": {
"userId": "P4SpYVd1KjBaF4SKyVw0E",
},
"timestamp": "2022-06-11T12:44:13.333Z",
"mood": "bad",
"_id": "62a352b83859aaf975c6332d",
},
"contactRequest": [
{
"timestamp": "2022-06-11T15:25:13.333Z",
"source" : {
"userId":"P4SpYVd1KjBaF4SKyVw0E"
},
"resolve": true,
"_id": "62a351ff3859aaf975c63329"
},
{
"timestamp": "2022-06-11T18:23:13.333Z",
"source" : {
"userId":"P4SpYVd1KjBaF4SKyVw0E"
},
"resolve": false,
"_id": "62a351ff3859aaf975c63329"
},
]
}
}
]
}
To achive that I've used $group parameter, but at some point I have to declare which field should be fetch to result document and I have problem with contatRequest fields.
{
$group: {
_id: {
$dateToString: {
format: '%Y-%m-%d',
date: '$timestamp',
},
},
mood: {
$push: {
_id: '$_id',
source: '$source',
type: '$mood',
timestamp: '$timestamp',
},
},
contactRequest: {
$push: {
_id: '$contactRequest._id',
source: '$contactRequest.source',
resolve: '$contactRequest.resolve',
timestamp: '$contactRequest.timestamp',
},
},
},
},
{
$project: {
_id: 0,
timestamp: '$_id',
mood: 1,
contactRequest: 1,
},
},
Sample database/collections/aggregation pipeline at mongoplayground.net.

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 update multiple objects in the array in mongoDB?

How to update multiple objects in the array in MongoDB? Assume that I am retrieving from the client an array of titles that need to be changed.
Example:
Data from client:
[0,3]
Document in the MongoDB:
[
{
_id: 0,
dishes: [
{ title: 0, in_stock: true },
{ title: 1, in_stock: false },
{ title: 2, in_stock: true },
{ title: 3, in_stock: false },
],
},
];
The result should be:
[
{
_id: 0,
dishes: [
{ title: 0, in_stock: false },
{ title: 1, in_stock: false },
{ title: 2, in_stock: true },
{ title: 3, in_stock: true },
],
},
];
You can simply put a aggregation pipeline in your update clause.
db.collection.update({},
[
{
"$addFields": {
"dishes": {
"$map": {
"input": "$dishes",
"as": "d",
"in": {
"$cond": {
"if": {
"$in": [
"$$d.title",
[
0,
3
]
]
},
"then": {
title: "$$d.title",
in_stock: {
"$not": [
"$$d.in_stock"
]
}
},
"else": "$$d"
}
}
}
}
}
}
])
Here is the Mongo playground for your reference.

how to get all fields in the query with aggregation

i am trying this aggregation i got the exact out put but not get all fields please solve my problem how to get all fields in following query
db.lights.aggregate({ $match: { CREATE_DATE: { $gte: ISODate("2018-01-24T20:05:30.000Z"), $lt: ISODate("2018-02-24T20:05:30.000Z") } } }, { $addFields: { offduration: { $divide: [{ $subtract: ["$RECEIVEDDATE", "$CREATE_DATE"] }, 3600000] } } }, { "$group": { _id: { SWITCHID: "$SWITCHID", STATUS: "$STATUS" }, avgduration: { $avg: "$offduration" }, SWITCHID: { $first: "$SWITCHID" }, CREATE_DATE: { $first: "$CREATE_DATE" }, RECEIVEDDATE: { $first: "$RECEIVEDDATE" }, STATUS: { $first: "$STATUS" }, offduration: { $first: "$offduration" }, } }, { $project: { _id: 0, SWI`TCHID: 1, CREATE_DATE: 1, RECEIVEDDATE: 1, STATUS: 1, avgduration: '$avgduration', offduration: '$offduration' } },{"$group" : { _id: { SWITCHID: "$SWITCHID" }, on_minus_off: { $sum:{ "$cond": [ { "$eq": ["$STATUS", "LIGHTS OFF"] }, "$avgduration", { $subtract: [ 0, "$avgduration" ] } ]}} }})

how to write the single query in the aggregation

i am trying this aggregation but how to write single query in this aggregations how to solve the questions. please suggest me .please suggest me two documents switchID are same . but STATUS different one STATUS IS :LIGHTS OFF another STATUS IS:LIGHTS ON . any possible add the query LIGHTS OFF avgduration - LIGHTS ON avgduration
db.lights.aggregate({
$match: {
CREATE_DATE: {
$gte: ISODate("2018-01-24T20:05:30.000Z"),
$lt: ISODate("2018-02-24T20:05:30.000Z")
}
}
}, {
$addFields: {
offduration: {
$divide: [{
$subtract: ["$RECEIVEDDATE", "$CREATE_DATE"]
}, 3600000]
}
}
}, {
"$group": {
_id: {
SWITCHID: "$SWITCHID",
STATUS: "$STATUS"
},
avgduration: {
$avg: "$offduration"
},
SWITCHID: {
$first: "$SWITCHID"
},
CREATE_DATE: {
$first: "$CREATE_DATE"
},
RECEIVEDDATE: {
$first: "$RECEIVEDDATE"
},
STATUS: {
$first: "$STATUS"
},
offduration: {
$first: "$offduration"
},
}
}, {
$project: {
_id: 1,
SWITCHID: 1,
CREATE_DATE: 1,
RECEIVEDDATE: 1,
STATUS: 1,
avgduration: '$avgduration',
offduration: '$offduration'
}
})
dblights.aggregate({"$group" : {
... _id: {
... SWITCHID: "$_id.SWITCHID"
... },
... on_minus_off: { $sum:{ "$cond": [
... { "$eq": [ "$_id.STATUS", "on" ] },
... "$avgduration",
... { $subtract: [ 0, "$avgduration" ] }
... ]}}
... }}
... ])

Categories

Resources