MongoDB Aggregation - Select only same value from array inside lookup - mongodb

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

Related

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

Mongo Sort Aggregation not working on Sub Document

Trying to sort the sub-key on the document.
Example of data from the pipeline. Incorrect sort order for subkey availability.startIso
{
"_id": "60e458d7b896de9c8e44d6c9",
"uid": "6233ed1d8b154aa79d1435b5",
"name": "Pale",
"phoneNumber": "+19999813917",
"profileMedia": {
"url": "https://storage.googleapis.com/refresh-me-dev.appspot.com/dummy_photos/dummy_1.jpg",
"type": "photo"
},
"createdIso": "2021-07-06T13:21:27.513Z",
"isDeleted": false,
"isFlagged": false,
"isBanned": false,
"isAdmin": false,
"isVendor": true,
"lastOpenedAppIso": "2021-07-06T13:21:27.513Z",
"vendorMeta": {
"servicesOffered": [
"swedish"
],
"location": [
0,
0
]
},
"distanceFromPoint": 0,
"availability": [
{
"_id": "60e458d7b896de9c8e44d6cc",
"uid": "dec97d4b1dea44f7b2fa45a5",
"vendorUid": "6233ed1d8b154aa79d1435b5",
"startIso": "2021-07-12T04:07:21.349Z",
"endIso": "2021-07-12T05:07:21.360Z"
},
{
"_id": "60e458d7b896de9c8e44d6ce",
"uid": "a5928ea5c18c4321bd6a9a9b",
"vendorUid": "6233ed1d8b154aa79d1435b5",
"startIso": "2021-07-11T01:52:18.323Z",
"endIso": "2021-07-11T02:52:18.335Z"
}
]
}
Example of the aggregation
let vendors = await mongoDb
.collection<User>(collectionNames.users)
.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [lat, lng] },
spherical: true,
maxDistance: 7500,
distanceField: "distanceFromPoint",
},
},
{
$match: { isVendor: true },
},
{
$match: { "vendorMeta.servicesOffered": { $in: services } },
},
{
$lookup: {
from: "vendor.availability",
localField: "uid",
foreignField: "vendorUid",
as: "availability",
},
},
{
$addFields: {
availability: {
$filter: {
input: "$availability",
as: "availability",
cond: { $and: [{ $gte: ["$$availability.startIso", nowIso] }, { $lte: ["$$availability.endIso", nDaysIso] }] },
},
},
},
},
{ $sort: { "availability.startIso": 1 } },
{ $match: { availability: { $ne: [] } } },
])
.toArray();
This is working as intended, $sort does not work on arrays and can't be used like this. What you can do is $unwind, then $sort and end by $grouping to restore the structure, like so:
[
// ...,
{
$unwind: "$availability"
},
{ $sort: { "availability.startIso": 1 } },
{
$group: {
_id: '$_id',
root: {$first: "$$ROOT"},
availability: {$push: '$availability'}
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
'$root',
{ availability: '$availability'}
]
}
}
}
]
Note that i removed the :
{ $match: { availability: { $ne: [] } } },
As it's no longer required because $unwind will remove those documents for you.

How to use project in nested array using $In to get Data

I want to get to use array for searching data in mongo
Here is my data
{
"_id": ObjectID("5f0d6e394556410d486f6828"),
"branchId": "exampleId",
"info": [
{
"date": "12-10-09",
"programs": [
{
"programId": "ObjectId1",
},
{
"programId": "ObjectId2",
},
{
"programId": "ObjectId3",
},
],
}
],
}
I want to find programId by using array here is my array
const programIdArr = ["ObjectId1","ObjectId2"]
I want out put
NOTE : I want to use programIdArr search in mySql we can use something like whereIn
{
"_id": ObjectID("5f0d6e394556410d486f6828"),
"branchId": "exampleId",
"info": [
{
"date": "12-10-09",
"programs": [
{
"programId": "ObjectId1",
},
{
"programId": "ObjectId2",
},
],
}
],
}
Here is what I try to do
const program =
Models.aggregate([
{ $match: { _id: Mongoose.Types.ObjectId('5f0d6e394556410d486f6828') } },
{
//for first project I already get where date = 12-10-09
$project: {
info: {
$filter: {
input: '$info',
as: 'info',
cond: { $eq: ['$$info.date', '12-10-09'] },
},
},
},
// in this project I try to filter programId by using programIdArr It doesn't work
$project: {
info: {
$filter: {
input: '$info.programs.programId',
as: 'programId',
cond: { $in: [programIdArr] },
},
},
},
},
{ $unwind: { path: '$info' } },
])
.exec()
As I read document $in it's return only true of false I try also try to use $all but It didn't work too.
You can try this
[{
$match: {
_id: ObjectId("5f0d6e394556410d486f6828")
}
}, {
$unwind: {
path: "$info",
preserveNullAndEmptyArrays: false
}
}, {
$project: {
branchId: 1,
"info.date": 1,
"info.programs": {
$filter: {
input: '$info.programs',
as: 'p',
cond: {
$in: ["$$p.programId", ["ObjectId1", "ObjectId2"]]
},
},
}
}
}, {
$group: {
_id: "$_id",
branchId: {
$first: "$branchId"
},
info: {
$addToSet: "$info"
}
}
}]
Working Mongo playground

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

MongoDB - group by on facet result

Provided I have following collections
Customers
[
{
uuid: "first",
culture: "it-it"
},
{
uuid: "second",
culture: "de-de"
}
]
Vehicles
[
{
model: "mymodel",
users: [
{
uuid: "first",
isOwner: true,
createdOn: "2019-05-15T06: 00: 00"
}
]
},
{
model: "mymodel",
users: [
{
uuid: "first",
isOwner: false,
createdOn: "2019-05-15T06: 00: 00"
},
{
uuid: "second",
isOwner: true,
createdOn: "2019-05-15T06: 00: 00"
}
]
}
]
And following query:
db.customers.aggregate([
{
$lookup: {
from: "vehicles",
let: {
uuid: "$uuid"
},
pipeline: [
{
$match: {
$expr: {
$in: [
"$$uuid",
"$users.uuid"
]
}
}
},
{
$project: {
model: 1,
users: {
$filter: {
input: "$users",
as: "user",
cond: {
$eq: [
"$$user.uuid",
"$$uuid"
]
}
}
}
}
},
{
$unwind: "$users"
},
{
$replaceRoot: {
newRoot: {
isOwner: "$users.isOwner",
createdOn: "$users.createdOn"
}
}
}
],
as: "vehicles"
}
},
{
$facet: {
"createdOn": [
{
$match: {
"vehicles": {
$elemMatch: {
isOwner: true,
$and: [
{
"createdOn": {
$gte: "2019-05-15T00: 00: 00"
}
},
{
"createdOn": {
$lt: "2019-05-16T00: 00: 00"
}
}
]
}
}
}
},
{
$project: {
culture: 1,
count: {
$size: "$vehicles"
}
}
},
{
$group: {
_id: 0,
"total": {
$sum: "$count"
}
}
}
]
}
},
{
$project: {
"CreatedOn": {
$arrayElemAt: [
"$CreatedOn.total",
0
]
}
}
}
])
I get following result:
[
{
"createdOn": 2
}
]
What I would like to achieve is a result as follows:
[
{
culture: "it-it",
results: {
"createdOn": 1
}
},
{
culture: "de-de",
results: {
"createdOn": 1
}
}
]
But I cannot seem to figure out where I can group so that I can get that result.
Can someone show me the way to do this?
The query is more complex with more metrics so this is a trimmed down version of what I have.
I tried grouping everywhere but fail to get the desired result I want.
The following query can get us the expected output:
db.customers.aggregate([
{
$lookup: {
"from": "vehicles",
"let": {
"uuid": "$uuid"
},
"pipeline": [
{
$unwind: "$users"
},
{
$match: {
$expr: {
$and: [
{
$eq: ["$users.uuid", "$$uuid"]
},
{
$eq: ["$users.isOwner", true]
},
{
$gte: ["$users.createdOn", "2019-05-15T00: 00: 00"]
},
{
$lte: ["$users.createdOn", "2019-05-16T00: 00: 00"]
}
]
}
}
},
{
$count:"totalVehicles"
}
],
as: "vehiclesInfo"
}
},
{
$unwind: {
"path": "$vehiclesInfo",
"preserveNullAndEmptyArrays": true
}
},
{
$group: {
"_id": "$culture",
"culture": {
$first: "$culture"
},
"createdOn": {
$sum: "$vehiclesInfo.totalVehicles"
}
}
},
{
$project: {
"_id": 0,
"culture": 1,
"results.createdOn": "$createdOn"
}
}
]).pretty()
Output:
{ "culture" : "de-de", "results" : { "createdOn" : 1 } }
{ "culture" : "it-it", "results" : { "createdOn" : 1 } }