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" ] }
... ]}}
... }}
... ])
Related
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,
},
},
]);
Assume I have the following document:
[
{
"callId": "17dac51e-125e-499e-9064-f20bd3b1a9d8",
"caller": {
"firstName": "Test",
"lastName": "Testing",
"phoneNumber": "1231231234"
},
"inquiries": [
{
"inquiryId": "b0d14381-ce75-49aa-a66a-c36ae20b72a8",
"routeHistory": [
{
"assignedUserId": "cfa0ffe9-c77d-4eec-87d7-4430f7772e81",
"routeDate": "2020-01-01T06:00:00.000Z",
"status": "routed"
},
{
"assignedUserId": "cfa0ffe9-c77d-4eec-87d7-4430f7772e81",
"routeDate": "2020-01-03T06:00:00.000Z",
"status": "ended"
}
]
},
{
"inquiryId": "9d743be9-7613-46d7-8f9b-a04b4b899b56",
"routeHistory": [
{
"assignedUserId": "cfa0ffe9-c77d-4eec-87d7-4430f7772e81",
"routeDate": "2020-01-01T06:00:00.000Z",
"status": "routed"
},
{
"assignedUserId": "cfa0ffe9-c77d-4eec-87d7-4430f7772e81",
"routeDate": "2020-01-03T06:00:00.000Z",
"status": "ended"
}
]
}
]
}
]
I want to get results where inquiries.routeHistory.routeDate is equal to the $max routeDate value in routeHistory. I would expect my results to look like the following:
[
{
"callId": "17dac51e-125e-499e-9064-f20bd3b1a9d8",
"caller": {
"firstName": "Test",
"lastName": "Testing",
"phoneNumber": "1231231234"
},
"inquiries": [
{
"inquiryId": "b0d14381-ce75-49aa-a66a-c36ae20b72a8",
"routeHistory": [
{
"assignedUserId": "cfa0ffe9-c77d-4eec-87d7-4430f7772e81",
"routeDate": "2020-01-03T06:00:00.000Z",
"status": "ended"
}
]
},
{
"inquiryId": "9d743be9-7613-46d7-8f9b-a04b4b899b56",
"routeHistory": [
{
"assignedUserId": "cfa0ffe9-c77d-4eec-87d7-4430f7772e81",
"routeDate": "2020-01-03T06:00:00.000Z",
"status": "ended"
}
]
}
]
}
]
Is there a clean way to do this in a single aggregate, so that additional $match criteria can be applied? One caveat is that I can only use operators supported by DocumentDB: https://docs.aws.amazon.com/documentdb/latest/developerguide/mongo-apis.html
I have tried the following code, but to no avail:
{
$addFields: {
maxDate: {
$max: '$inquiries.routeHistory.routeDate',
},
},
},
{
$addFields: {
routeHistory: [
{
$arrayElemAt: [
{
$filter: {
input: '$inquiries.routeHistory',
cond: {
$eq: ['$maxDate', '$$this.routeDate'
],
},
},
},
0,
],
},
],
},
}
You have to use $map to scan outer array and to $filter to compare inner array's elements against $max date:
db.collection.aggregate([
{
$addFields: {
inquiries: {
$map: {
input: "$inquiries",
as: "inquiry",
in: {
inquiryId: "$$inquiry.inquiryId",
routeHistory: {
$filter: {
input: "$$inquiry.routeHistory",
cond: {
$eq: [ { $max: "$$inquiry.routeHistory.routeDate" }, "$$this.routeDate" ]
}
}
}
}
}
}
}
}
])
Mongo Playground
EDIT: by looking at your link I've noticed that $map is not supported, you can use below combination as a workaround:
db.collection.aggregate([
{
$unwind: "$inquiries"
},
{
$addFields: {
"inquiries.routeHistory": {
$filter: {
input: "$inquiries.routeHistory",
cond: {
$eq: [ { $max: "$inquiries.routeHistory.routeDate" }, "$$this.routeDate" ]
}
}
}
}
},
{
$group: {
_id: "$_id",
callId: { $first: "$callId" },
caller: { $first: "$caller" },
inquiries: { $push: "$inquiries" }
}
}
])
Mongo Playground (2)
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" ] } ]}} }})
I am trying in this aggregation is working but not get all fields how to get all fields any suggestion me i wright any wrong this query please check
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"
}
}
}, {
$project: {
_id: 1,
SWITCHID: 1,
CREATE_DATE: 1,
RECEIVEDDATE: 1,
STATUS: 1,
avgduration: '$avgduration',
offduration: '$offduration'
}
})
try this,
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'
}
})
You can use $$ROOT also, It'll add entire object inside data. You have to refer using data.key
{
$group: {
_id: {
SWITCHID: "$SWITCHID",
STATUS: "$STATUS"
},
data: {
$first: "$$ROOT"
}
}
}
I am writing the first query greater than equal to CREATE_DATE and less then CREATE_DATE I got the answer ofter calculate the duration write another query but how to write the single query in the aggregation.
Query 1
db.lights.aggregate({
$match: {
CREATE_DATE: {
$gte: ISODate("2018-01-24T20:05:30.000Z"),
$lt: ISODate("2018-02-24T20:05:30.000Z")
}
}
});
Result
{
"_id": ObjectId("5a9a74843711955836a8b4b5"),
"SWITCHID": "Z4-W40-SS451A/4",
"CREATE_DATE": ISODate("2018-01-24T20:05:30Z"),
"RECEIVEDDATE": ISODate("2018-02-24T20:05:45Z"),
"STATUS": "LIGHTS ON"
}
Query 2
db.lights.aggregate([
{
$addFields: {
offduration: {
$divide: [
{
$subtract: [
"$RECEIVEDDATE",
"$CREATE_DATE"
]
},
3600000
]
}
}
}
]);
Result
{
"_id": ObjectId("5a9a75af3711955836a8b4c8"),
"SWITCHID": "Z4-W40-SS451A/5",
"CREATE_DATE": ISODate("2018-02-24T20:05:30Z"),
"RECEIVEDDATE": ISODate("2018-02-24T20:05:45Z"),
"STATUS": "LIGHTS ON",
"offduration": 0.004166666666666667
}
You need to improve your query like this :
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
]
}
}
},
{
$project: {
_id: 1,
SWITCHID: 1,
CREATE_DATE: 1,
RECEIVEDDATE: 1,
STATUS: 1,
offduration: '$offduration',
avgduration: { $avg: "$offduration" }
}
});