MongoDB nested Aggregate Grouping - mongodb

Sample Data:
[
{type: 'partial', jobId: '121', browser: 'chrome', status:'true', jobName:'one'},
{type: 'partial', jobId: '122', browser: 'chrome', status:'false', jobName:'two'},
{type: 'partial', jobId: '121', browser: 'firefox', status:'false', jobName:'one'},
{type: 'partial', jobId: '122', browser: 'firefox', status:'true', jobName:'two'},
{type: 'full', jobId: '123', browser: 'chrome', status:'true', jobName:'three'},
{type: 'full', jobId: '123', browser: 'chrome', status:'true', jobName:'three'},
{type: 'full', jobId: '123', browser: 'chrome', status:'false', jobName:'three'},
{type: 'full', jobId: '124', browser: 'firefox', status:'false', jobName:'four'},
]
Output Needed:
[
{
"type": "partial",
"browsers": [
{
"browser": "chrome",
"jobIds": [
{
"jobId": "121",
"results": [
{
"jobName": "one",
"status": "true",
},
]
},
{
"jobId": "122",
"results": [
{
"jobName": "two",
"status": "false"
},
]
}
]
},
{
"browser": "firefox",
"testIds": [
{
"jobId": "121",
"results": [
{
"jobName": "one",
"status": "false"
},
]
},
{
"jobId": "122",
"results": [
{
"jobName": "two",
"status": "true"
},
]
}
]
}
]
},
{
"type": "full",
"browsers": [
{
"browser": "chrome",
"jobIds": [
{
"jobId": "123",
"results": [
{
"jobName": "three",
"status": "true"
},
{
"jobName": "three",
"status": "true"
},
{
"jobName": "three",
"status": "false"
}
]
},
]
},
{
"browser": "firefox",
"testIds": [
{
"jobId": "124",
"results": [
{
"jobName": "four",
"status": "false"
},
]
},
]
}
]
}
]
I understand how to use group, but then I don't understand how to make the nested grouping. I tried the below query, it is not fetching needed results, I don't know how to proceed further.
db.collection.aggregate([
{
$match: {
jobId: {
"$exists": true
}
}
},
{
$sort: {
_id: -1
}
},
{
$group: {
_id: {
type: "$type",
browser: "$browser",
jobId: "$jobId"
},
results: {
$push: {
jobName: "$jobName",
status: "$status",
type: "$type",
jobId: "$jobId"
}
}
}
},
{
$addFields: {
results: {
$slice: [
"$results",
30
]
}
}
},
{
$group: {
_id: "$_id.browser",
results: {
$push: {
results: "$results"
}
}
}
},
])
Need fetch recent 30 results, that's why I added $addFields in query.
https://mongoplayground.net/p/pt3H1O445GA

$group by type, browser and jobId and make results array
$group by type and browser and make jobs array
$group by type and make browsers array
db.collection.aggregate([
{ $match: { jobId: { $exists: true } } },
{ $sort: { _id: -1 } },
{
$group: {
_id: {
type: "$type",
browser: "$browser",
jobId: "$jobId"
},
results: {
$push: {
jobName: "$jobName",
status: "$status"
}
}
}
},
{ $addFields: { results: { $slice: ["$results", 30] } } },
{
$group: {
_id: {
type: "$_id.type",
browser: "$_id.browser"
},
browser: { $first: "$_id.browser" },
jobIds: {
$push: {
jobId: "$_id.jobId",
results: "$results"
}
}
}
},
{
$group: {
_id: "$_id.type",
type: { $first: "$_id.type" },
browsers: {
$push: {
browser: "$_id.browser",
jobIds: "$jobIds"
}
}
}
},
{ $project: { _id: 0 } }
])
Playground

Related

mongodb - How to sort by distance using geoNear in addition to looking up another collection

I have two functionalities working individually but want to combine them.
Functionality 1 - Sort users by their geoNear distance.
Functionality 2 - The users should not have already been liked by the
current user (look up partnership collection)
How to update this query to start from the user's collection so I can do geoNear?
The output in the below mongoplayground is correct except that the resulting users are not sorted by calculatedDist which is a field calculated by geoNear.
$geoNear: {
near: { type: "Point", coordinates: [x,y },
distanceField: "calculatedDist",
spherical: true
}
geoNear needs location which is only available in users collection hence I think below query needs to be modified to start in user's collection.
https://mongoplayground.net/p/7H_NxciKezB
db={
users: [
{
_id: "abc",
name: "abc",
group: 1,
location: {
type: "Point",
coordinates: [
54.23,
67.12
]
},
calculatedDist: 13
},
{
_id: "xyz",
name: "xyyy",
group: 1,
location: {
type: "Point",
coordinates: [
54.23,
67.12
]
},
calculatedDist: 11
},
{
_id: "123",
name: "yyy",
group: 1,
location: {
type: "Point",
coordinates: [
54.23,
67.12
]
},
calculatedDist: 2
},
{
_id: "rrr",
name: "tttt",
group: 1,
location: {
type: "Point",
coordinates: [
54.23,
67.12
]
},
calculatedDist: 11
},
{
_id: "eee",
name: "uuu",
group: 1,
location: {
type: "Point",
coordinates: [
54.23,
67.12
]
},
calculatedDist: 7
},
],
partnership: [
{
_id: "abc_123",
fromUser: "abc",
toUser: "123"
},
{
_id: "eee_rrr",
fromUser: "eee",
toUser: "rrr"
},
{
_id: "rrr_abc",
fromUser: "rrr",
toUser: "abc"
},
{
_id: "abc_rrr",
fromUser: "abc",
toUser: "rrr"
},
{
_id: "xyz_rrr",
fromUser: "xyz",
toUser: "rrr"
},
{
_id: "rrr_eee",
fromUser: "rrr",
toUser: "eee"
},
]
}
geoNear as far as I know has to be the first thing to be done so my query should start with the users collection. This breaks my partnership check because for that to work, I start at partnership collection.
In the playground above, the user eee has a lesser calculated distance as a result of geoNear but it shows after user abc.
Try this out:
db.partnership.aggregate([
// $geoNear
{
$match: {
$or: [
{
fromUser: "rrr"
},
{
toUser: "rrr"
}
]
}
},
{
$group: {
_id: 0,
from: {
$addToSet: "$fromUser"
},
to: {
$addToSet: "$toUser"
}
}
},
{
$project: {
_id: 0,
users: {
$filter: {
input: {
$setIntersection: [
"$from",
"$to"
]
},
cond: {
$ne: [
"$$this",
"rrr"
]
}
}
}
}
},
{
$lookup: {
from: "users",
let: {
userId: "$users"
},
pipeline: [
{
"$geoNear": {
"near": {
"type": "Point",
"coordinates": [
31.4998,
-61.4065
]
},
"distanceField": "calculatedDist",
"spherical": true
}
},
{
"$match": {
"$expr": {
"$in": [
"$_id",
"$$userId"
]
}
}
}
],
as: "users"
}
},
{
$project: {
users: 1,
count: {
$size: "$users"
}
}
}
])
Here, we use the pipelined form of lookup.
The lookup is on the user's collection, in which we specify a pipeline with the $geoNear stage as the first stage.
And finally filter out and only keep the users belonging to a partnership.
This is the playground link. Let me know if it works, on the playground I can't test it because $geoNear requires a 2d index.
While using calculatedDist, it looks like this:
db.partnership.aggregate([
// $geoNear
{
$match: {
$or: [
{
fromUser: "rrr"
},
{
toUser: "rrr"
}
]
}
},
{
$group: {
_id: 0,
from: {
$addToSet: "$fromUser"
},
to: {
$addToSet: "$toUser"
}
}
},
{
$project: {
_id: 0,
users: {
$filter: {
input: {
$setIntersection: [
"$from",
"$to"
]
},
cond: {
$ne: [
"$$this",
"rrr"
]
}
}
}
}
},
{
$lookup: {
from: "users",
let: {
userId: "$users"
},
pipeline: [
{
$sort: {
calculatedDist: 1
}
},
{
"$match": {
"$expr": {
"$in": [
"$_id",
"$$userId"
]
}
}
}
],
as: "users"
}
},
{
$project: {
users: 1,
count: {
$size: "$users"
}
}
}
])
Playground.

MongoDB aggregate using $match with $expr with array

MongoDB 5.0.9
I am trying to get
value of application within course and their specification
value of paid application ( status : paid) based on course and their specification
courses collection having multiple courses with specification which might be there maybe not
[
{
"_id": {
"$oid": "62aab6669b3740313d881a30"
},
"course_name": "Master",
"fees": "Rs.1000.0/-",
"course_specialization": [
{
"spec_name": "Social Work",
"is_activated": true
}
],
"college_id": {
"$oid": "628dfd41ef796e8f757a5c13"
},
"is_pg": true
},
{
"_id": {
"$oid": "62aab6669b3740313d881a38"
},
"college_id": {
"$oid": "628dfd41ef796e8f757a5c13"
},
"course_name": "BBA",
"fees": "Rs.1000.0/-",
"is_pg": false,
"course_specialization": null
},
{
"_id": {
"$oid": "628f3967cb69fc0789e69181"
},
"course_name": "BTech",
"fees": "Rs.1000.0/-",
"course_specialization": [
{
"spec_name": "Computer Science and Engineering",
"is_activated": true
},
{
"spec_name": "Mutiple Specs",
"is_activated": true
}
],
"college_id": {
"$oid": "628dfd41ef796e8f757a5c13"
},
"is_pg": false
},
{
"_id": {
"$oid": "628f35a1cb69fc0789e6917e"
},
"course_name": "Bachelor",
"fees": "Rs.1000.0/-",
"course_specialization": [
{
"spec_name": "Social Work",
"is_activated": true
}
],
"college_id": {
"$oid": "628dfd41ef796e8f757a5c13"
},
"is_pg": false
}
],
Student Application forms collection where we are storing student application forms details
[
{
"_id": {
"$oid": "62cd476adbc878a0490e20ee"
},
"spec_name1": "Social Work",
"spec_name2": "",
"spec_name3": "",
"student_id": {
"$oid": "62cd1374dbc878a0490e20a5"
},
"course_id": {
"$oid": "62aab6669b3740313d881a30"
},
"current_stage": 2.5,
"declaration": true,
"payment_info": {
"payment_id": "123458",
"status": "paid"
},
"enquiry_date": {
"$date": {
"$numberLong": "1657620330432"
}
},
"last_updated_time": {
"$date": {
"$numberLong": "1657621796062"
}
}
},
{
"_id": {
"$oid": "62cd476adbc878a0490e20ef"
},
"spec_name1": "",
"spec_name2": "",
"spec_name3": "",
"student_id": {
"$oid": "62cd1374dbc878a0490e20a5"
},
"course_id": {
"$oid": "62aab6669b3740313d881a38"
},
"current_stage": 2.5,
"declaration": true,
"payment_info": {
"payment_id": "123458",
"status": "paid"
},
"enquiry_date": {
"$date": {
"$numberLong": "1657620330432"
}
},
"last_updated_time": {
"$date": {
"$numberLong": "1657621796062"
}
}
},
{
"_id": {
"$oid": "62cdc12000b820f5ea58cc60"
},
"spec_name1": "Social Work",
"spec_name2": "",
"spec_name3": "",
"student_id": {
"$oid": "62cdad90a9b64d58b15e6976"
},
"course_id": {
"$oid": "628f35a1cb69fc0789e6917e"
},
"current_stage": 6.25,
"declaration": false,
"payment_info": {
"payment_id": "",
"status": ""
},
"enquiry_date": {
"$date": {
"$numberLong": "1657651488511"
}
},
"last_updated_time": {
"$date": {
"$numberLong": "1657651987155"
}
}
}
]
Desired output with every specification within the course
[
"_id": {
"coursename": "Master",
"spec": "Social Work",
"Application_Count": 1,
"Paid_Application_Count:0
},
{
"_id": {
"coursename": "Bachelor"
"spec":"" ,
"Application_Count": 1,
"Paid_Application_Count:0
},
{
"_id": {
"coursename": "BBA"
"spec":"" ,
"Application_Count": 1,
"Paid_Application_Count:1
},
]
Aggregation Query
[{
$match: {
college_id: ObjectId('628dfd41ef796e8f757a5c13')
}
}, {
$project: {
_id: 1,
course_name: 1,
course_specialization: 1
}
}, {
$unwind: {
path: '$course_name',
includeArrayIndex: 'course_index',
preserveNullAndEmptyArrays: true
}
}, {
$unwind: {
path: '$course_specialization',
includeArrayIndex: 'course_specs_index',
preserveNullAndEmptyArrays: true
}
}, {
$lookup: {
from: 'studentApplicationForms',
'let': {
id: '$_id',
spec: '$course_specialization.spec_name'
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
'$course_id',
'$$id'
]
},
{
$eq: [
'$spec_name1',
'$$spec'
]
}
]
}
}
},
{
$project: {
student_id: 1,
payment_info: 1,
spec_name1: 1,
spec_name2: 1,
spec_name3: 1
}
}
],
as: 'student_application'
}
}, {
$unwind: {
path: '$student_application',
includeArrayIndex: 'application',
preserveNullAndEmptyArrays: true
}
}, {
$facet: {
course: [
{
$group: {
_id: {
course_name: '$course_name',
spec: '$course_specialization'
},
count: {
$count: {}
}
}
}
],
declatration: [
{
$group: {
_id: {
course_name: '$course_name',
spec: '$course_specialization'
},
count_dec: {
$sum: {
$cond: [
'$student_application.declaration',
1,
0
]
}
}
}
}
],
payment: [
{
$group: {
_id: {
course_name: '$course_name',
spec: '$course_specialization'
},
payment: {
$sum: {
$eq: [
'$student_application.payment_info.status',
'paid'
]
}
}
}
}
]
}
}]
Problem :
I am able to get application count but it is not getting unique value if 2 specs are same then duplicate value is coming as you can see on sample application collection Social Work is in two different course . So my aggregations is not grouping them based in course name.specs
Not able to find correct Paid_Application_Count and Application_Count
Update :
Updated JSON Data Matching use cases with different type of data
MongoDB Playground
You can do it in several different ways, I took the liberty to simplify the pipeline a little bit.
I will just mention that the structure does not fully make sense to me, and there are some additional contradictions between the sample input you provided and the "text" description/pipeline description.
Just a tiny example is payment_info_status being paid in the sample and capture in the pipeline.
These things will not change the pipeline structure, will just need to be fixed by you based on the actual needs.
db.courses.aggregate([
{
$project: {
_id: 1,
course_name: 1,
course_specialization: 1
}
},
{
$unwind: {
path: "$course_specialization",
preserveNullAndEmptyArrays: true
}
},
{
$lookup: {
from: "studentApplicationForms",
"let": {
courseId: "$_id",
spec: {
$ifNull: [
"$course_specialization.spec_name",
""
]
}
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$spec_name1",
"$$spec"
]
},
{
$eq: [
"$$courseId",
"$course_id"
]
}
]
}
}
},
{
$project: {
student_id: 1,
payment_info: 1,
spec_name1: 1,
spec_name2: 1,
spec_name3: 1,
declaration: 1,
}
},
{
$group: {
_id: null,
count: {
$sum: 1
},
declatration: {
$sum: {
$cond: [
"$declaration",
1,
0
]
}
},
paid: {
$sum: {
$cond: [
{
$eq: [
"$payment_info.status",
"paid"
]
},
1,
0
]
}
},
}
}
],
as: "student_application"
}
},
{
$project: {
_id: {
coursename: "$course_name",
spec: "$course_specialization.spec_name",
Application_count: {
$ifNull: [
{
$first: "$student_application.count"
},
0
]
},
Declaration_count: {
$ifNull: [
{
$first: "$student_application.declatration"
},
0
]
},
Paid_Application_Count: {
$ifNull: [
{
$first: "$student_application.paid"
},
0
]
},
}
}
}
])
Mongo Playground

MongoDB Aggregation - Select only same value from array inside lookup

I have aggregation like this:
Produk.aggregate([
{
$lookup: {
from: "kis_m_kategoriproduks",
localField: "idSubKategori",
foreignField: "subKategori._id",
as: "kategori",
},
},
{ $unwind: "$kategori" },
{ $sort: { produk: 1 } },
{
$project: {
_id: 0,
id: "$id",
dataKategori: {
idKategori: "$kategori._id",
kategori: "$kategori.kategori",
idSubKategori: "$idSubKategori",
subKategori: "$kategori.subKategori",
},
},
},
])
current result is :
{
"status": "success",
"data": [
{
"dataKategori": {
"idKategori": "6195bbec8ee419e6a9b8329d",
"kategori": "Kuliner",
"idSubKategori": "6195bc0f8ee419e6a9b832a2",
"subKategori": [
{
"nama": "Food",
"_id": "6195bc0f8ee419e6a9b832a2"
},
{
"nama": "Drink",
"_id": "6195bc258ee419e6a9b832a8"
}
]
}
}
]
}
I only want to display data in subKategori that the _id match with idSubKategori. this what I expected:
{
"status": "success",
"data": [
{
"dataKategori": {
"idKategori": "6195bbec8ee419e6a9b8329d",
"kategori": "Kuliner",
"idSubKategori": "6195bc0f8ee419e6a9b832a2",
"subKategori": [
{
"nama": "Food",
"_id": "6195bc0f8ee419e6a9b832a2"
}
]
}
}
]
}
here is my $kategori schema:
const schema = mongoose.Schema(
{
kategori: {
type: String,
required: true,
unique: true,
},
subKategori: [
{
id: mongoose.Types.ObjectId,
nama: String,
},
],
},
{
timestamps: false,
}
);
any suggestion?
I fix the problem by add $filter inside $project like this:
dataKategori: {
idKategori: "$kategori._id",
kategori: "$kategori.kategori",
subKategori: {
$arrayElemAt: [
{
$filter: {
input: "$kategori.subKategori",
as: "sub",
cond: { $eq: ["$$sub._id", "$idSubKategori"] },
},
},
0,
],
},
},
reference: https://stackoverflow.com/a/42490320/6412375

aggregation with group by, inner join and nested conditions in MongoDB

First of all I am sorry if this is a basic question, I am new to queries in MongoDB. Well, what I need is to find the latest registers for a worker in my WorkerLocationContext document and the latest register for each sensor in my HeatMeasureContext document, then join it by their location and then apply some filters. Here are my Schemas:
HeatMeasureContext:
const heatMeasureContextSchema = new mongoose.Schema({
sensor: { type: Schema.Types.ObjectId, ref: 'MeasureSensor', required: true },
humid: { type: Schema.Types.Number, required: true },
globe: { type: Schema.Types.Number, required: true },
mercury: { type: Schema.Types.Number, required: true },
internal: { type: Schema.Types.Number, required: true },
external: { type: Schema.Types.Number, required: true }
}, { timestamps: true })
MeasureSensor:
const measureSensorSchema = new mongoose.Schema({
name: { type: String, required: true },
description: { type: String, required: false },
type: { type: String, required: false, uppercase: true,
enumValues: ['MEASURE'], default: 'MEASURE' },
location: { type: Schema.Types.ObjectId, ref: 'Location' },
sensorType: { type: String, required: false, uppercase: true,
enumValues: ['WORKER_ATTACHED', 'ENVIRONMENT'], default: 'ENVIRONMENT' },
measurerType: { type: String, required: false, uppercase: true,
enumValues: ['HEAT', 'RUID'] },
placementType: { type: String, required: false, uppercase: true,
enumValues: ['INTERNAL', 'EXTERNAL'], default: 'INTERNAL' }
})
WorkerLocationContext:
const workerLocationContextSchema = new mongoose.Schema({
sensor: { type: Schema.Types.ObjectId, ref: 'LocationSensor', required: true },
worker: { type: Schema.Types.ObjectId, ref: 'Worker', required: true }
}, { timestamps: true })
Location
const locationSchema = new mongoose.Schema({
name: { type: String, required: true },
description: { type: String, required: false },
type: { type: String, required: false, uppercase: true,
enumValues: ['REST', 'ROOM', 'COURTYARD'], default: 'ROOM' }
})
Worker
const workerSchema = new mongoose.Schema({
name: { type: String, required: true },
workGroup: { type: Schema.Types.ObjectId, ref: 'WorkGroup', required: false }
})
I have built my query like this:
WorkerLocationContext.aggregate([
{
"$lookup": {
"from": "HeatMeasureContext",
"localField": "sensor.location._id",
"foreignField": "sensor.location._id",
"as": "HMContext"
}
},
{
"$match": {
"$and": [
{ "$or": [
{ "$and": [
{
"HMContext.sensor.placementType": { "$eq": "INTERNAL" }},
{"HMContext.internal": { "$gte": limit}
},
{
"HMContext.sensor.placementType": { "$eq": "EXTERNAL" }},
{"HMContext.external": { "$gte": limit}
},
]},
]},
{ "WorkerLocationContext.worker.location.type": { "$ne": "REST" } }
]
}
},
{
"$group": {
"_id": "null",
"workers": {
"$count": {}
},
"hmDatetime": {
"$max": "$HMContext.createdAt"
},
"wlDatetime": {
"$max": "$WorkerLocationContext.createdAt"
}
}
}
]);
Basically, my goal with it is to count how many workers fit in that condition according to their current location, thus the latest registers in the context tables. I have tried some simulations in the mongoplayground, but nothing succeeded. Is it possible to be done in MongoDB? Can you help me?
Thanks in advance!
Edit 1
Sample Data
- Worker
[
{ "_id": "6181de993fca98374cf901f6", "name": "Worker 1", "workGroup": "6181de3e3fca98374cf901f4", "__v": 0 },
{ "_id": "6181dec33fca98374cf901f7", "name": "Worker 2", "workGroup": "6181de4a3fca98374cf901f5", "__v": 0 },
{ "_id": "6181decc3fca98374cf901f8", "name": "Worker 3", "workGroup": "6181de4a3fca98374cf901f5", "__v": 0 },
{ "_id": "6181ded13fca98374cf901f9", "name": "Worker 4", "workGroup": "6181de4a3fca98374cf901f5", "__v": 0 }
]
- Location
[
{ "_id": "6181df293fca98374cf901fa", "name": "Location 1", "description": "Rest place", "__v": 0, "type": "ROOM" },
{ "_id": "6181df3b3fca98374cf901fb", "name": "Location 2", "description": "Room 1", "__v": 0, "type": "ROOM" }
]
- MeasureSensor
[
{ "_id": "6181e5ae3fca98374cf901fc", "name": "Sensor 1", "description": "Heat Sensor 1", "location": "6181df3b3fca98374cf901fb", "measurerType": "HEAT", "__v": 0, "placementType": "INTERNAL", "sensorType": "ENVIRONMENT", "type": "MEASURE" }
]
- LocationSensor
[
{ "_id": "6181e5f83fca98374cf901fd", "name": "Location Sensor 1", "description": "Location sensor for Location 2", "location": "6181df3b3fca98374cf901fb", "trackerType": "RFID", "__v": 0, "sensorType": "ENVIRONMENT", "type": "LOCATION" }
]
- WorkerLocationContext
[
{ "_id": "615676c885ccad55a493503b", "updatedAt": "2021-10-01T02:47:36.207Z", "createdAt": "2021-10-01T02:47:36.207Z", "sensor": "615657572079a55f7814947b", "worker": "6153dcfb58ad722c747eb42d", "__v": 0 },
{ "_id": "618311b56b77f445ecf73277", "updatedAt": "2021-11-03T22:48:21.887Z", "createdAt": "2021-11-03T22:48:21.887Z", "sensor": "6181e5f83fca98374cf901fd", "worker": "6181de993fca98374cf901f6", "__v": 0 },
{ "_id": "618311c86b77f445ecf73278", "updatedAt": "2021-11-03T22:48:40.507Z", "createdAt": "2021-11-03T22:48:40.507Z", "sensor": "6181e5f83fca98374cf901fd", "worker": "6181decc3fca98374cf901f8", "__v": 0 }
]
- HeatMeasureContext
[
{ "_id": "61831b796b77f445ecf7327b", "updatedAt": "2021-11-03T23:30:01.640Z", "createdAt": "2021-11-03T23:30:01.640Z", "sensor": "6181e5ae3fca98374cf901fc", "mercury": 25.8, "humid": 23.5, "globe": 25.5, "external": 24.13, "internal": 24.1, "__v": 0 },
{ "_id": "61831bc96b77f445ecf7327c", "updatedAt": "2021-11-03T23:31:21.080Z", "createdAt": "2021-11-03T23:31:21.080Z", "sensor": "6181e5ae3fca98374cf901fc", "mercury": 28.6, "humid": 27.8, "globe": 27, "external": 27.72, "internal": 27.56, "__v": 0 }
]
Edit 2
I had to simplify a bit my query because some expressions like heatMeasureContex.sensor.location wouldn't work in there (as far as I know), but here is a simple trial that is not working, and isn't even the half of what I need: mongopplaygroung.net
You can start an aggregation pipeline from the HeatMeasureContext collection:
$match on the internal or external field
$lookup the WorkerLocationContext collection using an sub-pipeline. In the sub-pipeline, $sum the worker count and get the $max wlDatetime
$unwind the result for further processing
$group again on HeatMeasureContext.location, use $first to get the result in sub-pipeline and $max to get the hmDatetime
db.HeatMeasureContext.aggregate([
{
$match: {
$expr: {
$or: [
{
$gte: [
"$internal",
27
]
},
{
$gte: [
"$external",
27
]
}
]
}
}
},
{
"$lookup": {
"from": "WorkerLocationContext",
let: {
loc: "$location"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$$loc",
"$location"
]
}
}
},
{
$group: {
_id: "$location",
"workers": {
"$sum": 1
},
"wlDatetime": {
"$max": "$createdAt"
}
}
}
],
"as": "workerAggResult"
}
},
{
$unwind: "$workerAggResult"
},
{
$group: {
_id: "$location",
"hmDatetime": {
$max: "$createdAt"
},
"wlDatetime": {
$first: "$workerAggResult.wlDatetime"
},
"workers": {
$first: "$workerAggResult.workers"
}
}
}
])
Here is the Mongo playground for your reference.
Well, after some studying and going through the MongoDB University Aggregation Framework course (which I found out to be very good, I highly recommend), I was able to figure how to do what I needed:
db.heatmeasurecontexts.aggregate([
{
'$group': {
'_id': '$sensor',
'createdAt': {
'$last': '$createdAt'
},
'external': {
'$last': '$external'
},
'internal': {
'$last': '$internal'
}
}
}, {
'$lookup': {
'from': 'measuresensors',
'localField': '_id',
'foreignField': '_id',
'as': 'sensor'
}
}, {
'$unwind': {
'path': '$sensor'
}
}, {
'$match': {
'$or': [
{
'$and': [
{
'sensor.placementType': {
'$eq': 'INTERNAL'
}
}, {
'internal': {
'$gte': 27
}
}
]
}, {
'$and': [
{
'sensor.placementType': {
'$eq': 'EXTERNAL'
}
}, {
'external': {
'$gte': 25
}
}
]
}
]
}
}, {
'$project': {
'_id': 0,
'measure_sensor_location': '$sensor.location'
}
}, {
'$lookup': {
'from': 'locationsensors',
'localField': 'measure_sensor_location',
'foreignField': 'location',
'as': 'location_sensor'
}
}, {
'$unwind': {
'path': '$location_sensor'
}
}, {
'$lookup': {
'from': 'workerlocationcontexts',
'localField': 'location_sensor._id',
'foreignField': 'sensor',
'as': 'worker_location_context'
}
}, {
'$unwind': {
'path': '$worker_location_context'
}
}, {
'$project': {
'worker_location_context': 1,
'location_sensor': 1
}
}, {
'$lookup': {
'from': 'workers',
'localField': 'worker_location_context.worker',
'foreignField': '_id',
'as': 'worker_location_context.worker'
}
}, {
'$unwind': {
'path': '$worker_location_context.worker'
}
}, {
'$match': {
'$expr': {
'$eq': [
'$location_sensor.location', '$worker_location_context.worker.currentLocation'
]
}
}
}, {
'$group': {
'_id': {
'sensor': '$worker_location_context.sensor',
'sensor_location': '$location_sensor.location',
'worker': '$worker_location_context.worker._id',
'worker_location': '$worker_location_context.worker.currentLocation'
},
'createdAt': {
'$last': '$worker_location_context.createdAt'
}
}
}, {
'$count': 'workers_at_risk'
}
])
I hope it may be useful eventually, despite the fact that this is a very specific scenario.

Mongoose aggregate with nested collection

I have following schemas.
First: AdditionalFieldSchema
const AdditionalFieldSchema = new Schema({
names: [
{
type: Schema.Types.ObjectId,
ref: "multiLanguageContent",
required: true
}
],
...
});
Second: MultiLanguageContentSchema
const MultiLanguageContentSchema = new Schema({
value: {
type: String,
required: true
},
...
});
and I have the following mongoose aggregate query.
The goal is to fetch every employees with their additionalField attached.
const employees = await Employee.aggregate([
{
$match: {
status: "active",
$nor: [
{ email: "blablabla" },
{ email: "blobloblo" }
]
}
},
{
$lookup: {
from: AdditionalField.collection.name,
let: { af_id: "$_id" },
pipeline: [{
$match: {
$expr: {
$and: [
{ $eq: ["$ownership", "$$af_id"] },
{ $eq: ["$status", "active"] },
{ $eq: ["$functionalType", "blablabla"] }
]
}
}
}],
as: "afs"
}
},
{ $unwind: "$afs" },
{ $unwind: "$afs.names" },
{
$group: {
_id: "$_id",
email: { $first: "$email" },
afs: {
$push: {
value: "$afs.value",
names: "$afs.names"
}
}
}
}
]);
The query I run to test this aggregate function.
query TestQuery {
testQuery
{
email
afs {
names {
value
}
value
}
}
}
The result I have.
"data": {
"testQuery": [
{
"email": "blablabla#test.com"
"afs": [
{
"names": [
{
"value": "Name 1"
}
],
"value": "Value 1"
},
{
"names": [
{
"value": "Name 2"
}
],
"value": "Value 2"
},
...
]
},
...
Result is good, I have data I want.
But I would like to have a result like this below
"data": {
"testQuery": [
{
"email": "blablabla#test.com",
"afs": [
{
"names": "Name 1",
"value": "Value 1"
},
{
"names": "Name 2",
"value": "Value 2"
},
...
]
},
...
It seems like { $unwind: "$afs.names" }, is not working.
Any ideas ?
Thanks, Flo