mongodb aggregate function and return the result based on the condition - mongodb

I had two tables vendors and vendorgs.
My condition below,
1.vendors table vendorOrgId === vendorgs table _id
2.status === "active" in vendorgs table
if above condition are satisficed the group the vendors by vendorgs table category.
Is possible to do that
vendors table
const vendors = [{
"name" : "Alfred",
"location" : "FH",
"vendorOrgId" : "1"
},
{
"name" : "Alfred",
"location" : "ADH",
"vendorOrgId" : "2"
},
{
"name" : "Alfred",
"location" : "AFF",
"vendorOrgId" : "41"
}]
vendorgs table
const vendorgs = [
{
"orgName" : "star super market",
"_id" : "1",
"category" : "grocery",
"status" : "active"
},
{
"orgName" : "L.f super market",
"_id" : "41",
"category" : "grocery",
"status" : "active"
},
{
"orgName" : "Fresh mart",
"_id" : "2",
"category" : "Milk",
"status" : "active"
}
]
My Query
db.getCollection('vendors').aggregate([{
"$lookup": {
"from": "vendorgs",
"localField": "vendorOrgId",
"foreignField": "_id",
"as": "data"
},
},
{
"$group": {
"_id": "$data.category",
"category":{"$push":"$data"},
}
},
{
"$match": {
"category.status":true
}
}
])
above query returning empty array
expected result
{
"grocery": [{
"name": "Alfred",
"location": "FH",
"vendorOrgId": "1"
},
{
"name": "Alfred",
"location": "AFF",
"vendorOrgId": "41"
}
],
"milk": [{
"name": "Alfred",
"location": "ADH",
"vendorOrgId": "2"
}]
}
Thanks!!

finally found answer at myself . should write match before group by
db.getCollection('vendors').aggregate([{
"$lookup": {
"from": "vendorgs",
"localField": "vendorOrgId",
"foreignField": "_id",
"as": "data"
},
},
{
"$match": {
"status":"active"
}
},
{
"$group": {
"_id": "$data.category",
"category":{"$push":"$data"},
}
}
])

Related

How to join two table in mongodb with aggregate and lookup I have as array in second table?

I have two collections:
clients
{
"_id" : ObjectId("60d203145b7b6c19b00ba576"),
"isDeleted" : false,
"createdAt" : ISODate("2021-06-22T15:06:21.564Z"),
"status" : "live",
"customerGUID" : "C8B910A3F74E",
"apps" : [
{
"url" : "https://test.com",
"loginGUID" : "12324654",
"loginAPIAccessKey" : "B072-266C369743CA",
}
],
"avatar" : "",
"description" : "",
"firstName" : "firstname",
"lastName" : "lastname",
"email" : "company#test.com",
"companyName" : "Company name",
}
visitors
{
"_id" : ObjectId("60aed4e0d6e30865f060be3c"),
"lastName" : "CAIN",
"firstName" : "DAVID",
"loginAPIAccessKey" : "B072-266C369743CA",
"email" : "cainins#att.net",
"createdAt" : ISODate("2021-05-26T23:08:16.505Z"),
"activity" : []
}
I want all visitors which have active clients with isDeleted: false status. and the relationship between visitors and clients is visitors.loginAPIAccessKey and clients.apps.loginAPIAccessKey which is in an array of objects.
Can someone help me?
You have to make use of the $lookup stage with the pipeline option.
db.visitors.aggregate([
{
"$lookup": {
"from": "clients",
"let": {
"loginAPIAccessKey": "$loginAPIAccessKey"
},
"pipeline": [
{
"$unwind": "$apps"
},
{
"$match": {
"$expr": {
"$eq": [
"$apps.loginAPIAccessKey",
"$$loginAPIAccessKey"
],
},
"isDeleted": false,
},
},
],
"as": "matchedClients"
}
},
{
"$match": {
"matchedClients": {
"$ne": []
}
},
},
])

How to use $lookup and $in mongodb aggregate

Colleges
{
"_id" : ObjectId("5cd42b5c65b41027845938ae"),
"clgID" : "100",
"name" : "Vivekananda"
},
{
"_id" : ObjectId("5cd42b5c65b41027845938ad"),
"clgID" : "200",
"name" : "National"
}
Point : 1 => Take all clgID From Colleges collection.
Subjects:
{
"_id" : ObjectId("5cd42c2465b41027845938b0"),
"name" : "Hindi",
"members" : {
"student" : [
"123"
]
},
"college" : {
"collegeID" : "100"
}
},
{
"_id" : ObjectId("5cd42c2465b41027845938af"),
"name" : "English",
"members" : {
"student" : [
"456",
"789"
]
},
"college" : {
"collegeID" : "100"
}
}
Point : 2 => Subjects collection we are mapped clgID under college.collegeID, Subjects collection we need to take the values of members.student based on clgID.
CollegeProducts
{
"_id" : "123",
"StudentProdcutID" : "123",
"StudentID" : "FF80",
"CID" : "Facebook"
},
{
"_id" : "456",
"StudentProdcutID" : "456",
"StudentID" : "FF81",
"CID" : "Facebook"
},
{
"_id" : "789",
"StudentProdcutID" : "789",
"StudentID" : "FF82",
"CID" : "Facebook"
}
Point : 3 => CollegeProducts collection we are mapped members.student values under StudentProdcutID, CollegeProducts collection we need to take the values in StudentID. CollegeProducts collection we need to check condition CID should be Facebook and take the values of StudentID based on members.student.
UserDetails
{
"name" : "A",
"StudentID" : "FF80"
},
{
"name" : "B",
"StudentID" : "FF81"
},
{
"name" : "C",
"StudentID" : "FF82"
}
Point : 3 => UserDetails collection we are mapped StudentID values under StudentID, UserDetails collection we need to take the values of name.
Expected Output:
{
"collegeName" : "National",
"StudentName" : "A"
},
{
"collegeName" : "National",
"StudentName" : "B"
},
{
"collegeName" : "National",
"StudentName" : "C"
}
My Code
db.Colleges.aggregate([
{ "$match": { "clgID": { "$in": ["100", "200"] }}},
{ "$lookup": {
"from": "Subjects",
"localField": "clgID",
"foreignField": "college.collegeID",
"as": "clg"
}},
{ "$unwind": { "path": "$clg", "preserveNullAndEmptyArrays": true }},
{ "$group": {
"_id": { "clgId": "$clg.college.collegeID", "_id": "$_id" },
"groupDetails": { "$push": "$clg.members.student" },
"clgName": { "$first": "$name" }
}},
{ "$project": {
"_id": "$_id._id",
"clgName": 1,
"groupDetails": {
"$reduce": {
"input": "$groupDetails",
"initialValue": [],
"in": { "$concatArrays": ["$$this", "$$value"] }
}
}
}}
])
I am not getting my expected output,kindly help me anyone. i am using mongodb version3.4
Don't bother grouping if you want the the each output to be one user, you're just doing double the work.
Change your query to this:
{
"$match" : {
"clgID" : {
"$in" : [
"100",
"200"
]
}
}
},
{
"$lookup" : {
"from" : "Subjects",
"localField" : "clgID",
"foreignField" : "college.collegeID",
"as" : "clg"
}
},
{
"$unwind" : {
"path" : "$clg",
"preserveNullAndEmptyArrays" : true
}
},
{
"$unwind" : {
"path" : "$clg.members.student",
"preserveNullAndEmptyArrays" : true
}
},
{
"$project" : {
"collegeName" : "$name",
"student" : "$clg.members.student"
}
}
],
Now with the second unwind each object contains the college name and -ONE- student so all we need to do now is project in the required form.
EDIT: full query according to request
{
"$match" : {
"clgID" : {
"$in" : [
"100",
"200"
]
}
}
},
{
"$lookup" : {
"from" : "Subjects",
"localField" : "clgID",
"foreignField" : "college.collegeID",
"as" : "clg"
}
},
{
"$unwind" : {
"path" : "$clg",
"preserveNullAndEmptyArrays" : true
}
},
{
"$unwind" : {
"path" : "$clg.members.student",
"preserveNullAndEmptyArrays" : true
}
},
{
"$lookup" : {
"from" : "CollegeProducts",
"localField" : "clg.members.student",
"foreignField" : "StudentProdcutID",
"as" : "clgproduct"
}
},
{ // can skip this unwind if theres always only one match.
"$unwind" : {
"path" : "$clgproduct",
"preserveNullAndEmptyArrays" : true
}
},
{
"$match" : {
"clgproduct.CID" : "Facebook"
}
},
{
"$lookup" : {
"from" : "UserDetails",
"localField" : "clgproduct.StudentID",
"foreignField" : "StudentID",
"as" : "student"
}
},
{ // can skip this unwind if theres always only one user matched.
"$unwind" : {
"path" : "$student",
"preserveNullAndEmptyArrays" : true
}
},
{
"$project" : {
"collegeName" : "$name",
"student" : "$student.name"
}
}
],
You can use below aggregation
db.Colleges.aggregate([
{ "$match": { "clgID": { "$in": ["100", "200"] }}},
{ "$lookup": {
"from": "Subjects",
"localField": "clgID",
"foreignField": "college.collegeID",
"as": "clg"
}},
{ "$unwind": { "path": "$clg", "preserveNullAndEmptyArrays": true }},
{ "$group": {
"_id": { "clgId": "$clg.college.collegeID", "_id": "$_id" },
"groupDetails": { "$push": "$clg.members.student" },
"clgName": { "$first": "$name" }
}},
{ "$project": {
"_id": "$_id._id",
"clgName": 1,
"groupDetails": {
"$reduce": {
"input": "$groupDetails",
"initialValue": [],
"in": { "$concatArrays": ["$$this", "$$value"] }
}
}
}},
{ "$lookup": {
"from": "CollegeProduct",
"localField": "groupDetails",
"foreignField": "StudentProdcutID",
"as": "CollegeProduct"
}},
{ "$unwind": "$CollegeProduct" },
{ "$lookup": {
"from": "UserDetails",
"localField": "CollegeProduct.StudentID",
"foreignField": "StudentID",
"as": "Student"
}},
{ "$unwind": "$Student" },
{ "$project": { "collegeName": "clgName", "StudentName": "$Student.name" }}
])
MongoPlayground
Output
[
{
"StudentName": "A",
"_id": ObjectId("5cd42b5c65b41027845938ae"),
"collegeName": "clgName"
},
{
"StudentName": "B",
"_id": ObjectId("5cd42b5c65b41027845938ae"),
"collegeName": "clgName"
},
{
"StudentName": "C",
"_id": ObjectId("5cd42b5c65b41027845938ae"),
"collegeName": "clgName"
}
]

Lookup on array of ids mongodb

I've made several searches before posting, but I'm currently facing an issue.
I am working with Mongo 4 with Symfony4 and Mongo-odm. I need to correct my shell query, I will adapt it to doctrine-odm then.
I've two collections like that :
circuit :
{
"_id" : "5c6e6f7be05bd900a1682582",
"name" : "Awesome name",
"startDate" : ISODate("2019-02-13T05:48:24.000Z"),
"endDate" : ISODate("2019-02-13T12:30:50.000Z"),
"state" : "closed",
"type" : "I",
"agency" : "5c6cfe7ae05bd9007477f7ee",
"drivers" : [
"5c6cfe99e05bd90074783c99",
"5c6cfe99e05bd90074784d85",
],
"exportedAt" : ISODate("2019-02-13T12:32:02.000Z"),
"createdAt" : ISODate("2019-02-21T09:29:31.783Z"),
"updatedAt" : ISODate("2019-02-21T09:29:31.783Z"),
"messages" : [
"5c6e7125e05bd900a1683595",
"5c6e7125e05bd900a1683596",
"5c6e7125e05bd900a1683597",
"5c6e7126e05bd900a1683598"
],
"orders" : [
"5c6d0269e05bd900747a559c",
"5c6d0269e05bd900747a559c",
"5c6d0269e05bd900747a559c"
]
}
order :
{
"_id" : "5c6d04a9e05bd900747a7c40",
"startDate" : ISODate("2019-02-19T08:35:04.000Z"),
"endDate" : ISODate("2019-02-19T12:53:50.000Z"),
"state" : "closed",
"company" : 1982,
"weight" : 960.0,
"type" : "E",
"circuit" : "5c6d0307e05bd900747a6c39",
"agency" : "5c6cfe79e05bd9007477f580",
"client" : "5c6d0074e05bd9007479a7c1",
"createdAt" : ISODate("2019-02-20T19:45:54.392Z"),
"updatedAt" : ISODate("2019-02-20T19:45:54.392Z"),
}
From circuit, I want to retrieve orders documents instead of their id.
I tried request like that :
db.circuit.aggregate([
{ "$match":
{ "agency":
{ "$in":
[
"5c6cfe79e05bd9007477f559", "5c6cfe79e05bd9007477f55b", "5c6cfe79e05bd9007477f562", "5c6cfe79e05bd9007477f563", "5c6cfe79e05bd9007477f565",
"5c6cfe79e05bd9007477f566", "5c6cfe79e05bd9007477f57e", "5c6cfe79e05bd9007477f57f", "5c6cfe79e05bd9007477f580", "5c6cfe79e05bd9007477f582",
"5c6cfe79e05bd9007477f587", "5c6cfe79e05bd9007477f588", "5c6cfe79e05bd9007477f589", "5c6cfe79e05bd9007477f58a", "5c6cfe79e05bd9007477f590",
"5c6cfe79e05bd9007477f591", "5c6cfe79e05bd9007477f592", "5c6cfe79e05bd9007477f593", "5c6cfe79e05bd9007477f594", "5c6cfe79e05bd9007477f595",
"5c6cfe79e05bd9007477f596", "5c6cfe79e05bd9007477f59b", "5c6cfe79e05bd9007477f59c", "5c6cfe79e05bd9007477f5af", "5c6cfe79e05bd9007477f5b2",
"5c6cfe79e05bd9007477f5e5", "5c6cfe79e05bd9007477f66d", "5c6cfe79e05bd9007477f679"
]
}
}
},
{
"$lookup":
{
"from": "agency",
"localField": "agency",
"foreignField": "_id",
"as": "agency"
}
},
{"$unwind": "$agency"},
{
"$lookup":
{
"from": "order",
"localField": "orders",
"foreignField": "_id",
"as": "sub_orders"
}
},
{
$unwind: {
path: "$sub_orders",
preserveNullAndEmptyArrays: true
}
},
{
"$project":
{
"name": "$$ROOT.nom",
"startDate": "$$ROOT.startDate",
"endDate": "$$ROOT.endDate",
"state": "$$ROOT.state",
"type": "$$ROOT.type",
"agencyName": "$agency.name",
"sub_orders": "$sub_orders"
}
}
]);
Unfortunately, I just retrieve the first document of the array id of orders like that :
{
"_id" : "5c6e6f9ee05bd900a168268f",
"name" : "Circuit",
"startDate" : ISODate("2019-02-13T06:18:28.000Z"),
"endDate" : ISODate("2019-02-13T11:40:12.000Z"),
"state" : "closed",
"type" : "I",
"agencyName" : "Amazing Agency",
"sub_orders" : {
"_id" : "5c6d04a9e05bd900747a7c40",
"startDate" : ISODate("2019-02-19T08:35:04.000Z"),
"endDate" : ISODate("2019-02-19T12:53:50.000Z"),
"state" : "closed",
"company" : 1982,
"weight" : 960.0,
"type" : "E",
"circuit" : "5c6d0307e05bd900747a6c39",
"agency" : "5c6cfe79e05bd9007477f580",
"client" : "5c6d0074e05bd9007479a7c1",
"createdAt" : ISODate("2019-02-20T19:45:54.392Z"),
"updatedAt" : ISODate("2019-02-20T19:45:54.392Z"),
}
}
However I want to get as many order document as id in array ids like :
{
"_id" : "5c6e6f9ee05bd900a168268f",
"name" : "Circuit",
"startDate" : ISODate("2019-02-13T06:18:28.000Z"),
"endDate" : ISODate("2019-02-13T11:40:12.000Z"),
"state" : "closed",
"type" : "I",
"agencyName" : "Amazing Agency",
"sub_orders" : {
"_id" : "5c6d04a9e05bd900747a7c40",
"startDate" : ISODate("2019-02-19T08:35:04.000Z"),
"endDate" : ISODate("2019-02-19T12:53:50.000Z"),
"state" : "closed",
"company" : 1982,
"weight" : 960.0,
"type" : "E",
"createdAt" : ISODate("2019-02-20T19:45:54.392Z"),
"updatedAt" : ISODate("2019-02-20T19:45:54.392Z"),
},{
"_id" : ".....",
"startDate" : ISODate("2019-02-19T08:35:04.000Z"),
"endDate" : ISODate("2019-02-19T12:53:50.000Z"),
"state" : "closed",
"company" : 1982,
"weight" : 960.0,
"type" : "E",
"createdAt" : ISODate("2019-02-20T19:45:54.392Z"),
"updatedAt" : ISODate("2019-02-20T19:45:54.392Z"),
},{
"_id" : ".....",
"startDate" : ISODate("2019-02-19T08:35:04.000Z"),
"endDate" : ISODate("2019-02-19T12:53:50.000Z"),
"state" : "closed",
"company" : 1982,
"weight" : 960.0,
"type" : "E",
"createdAt" : ISODate("2019-02-20T19:45:54.392Z"),
"updatedAt" : ISODate("2019-02-20T19:45:54.392Z"),
}
}
Thanks for saving me ! :)
I managed to do what i wanted to with the following query, it takes me few hours... :)
db.circuit.aggregate([
{ "$match":
{ "agency":
{ "$in":
[
"5c6cfe79e05bd9007477f559", "5c6cfe79e05bd9007477f55b", "5c6cfe79e05bd9007477f562", "5c6cfe79e05bd9007477f563", "5c6cfe79e05bd9007477f565",
"5c6cfe79e05bd9007477f566", "5c6cfe79e05bd9007477f57e", "5c6cfe79e05bd9007477f57f", "5c6cfe79e05bd9007477f580", "5c6cfe79e05bd9007477f582",
"5c6cfe79e05bd9007477f587", "5c6cfe79e05bd9007477f588", "5c6cfe79e05bd9007477f589", "5c6cfe79e05bd9007477f58a", "5c6cfe79e05bd9007477f590",
"5c6cfe79e05bd9007477f591", "5c6cfe79e05bd9007477f592", "5c6cfe79e05bd9007477f593", "5c6cfe79e05bd9007477f594", "5c6cfe79e05bd9007477f595",
"5c6cfe79e05bd9007477f596", "5c6cfe79e05bd9007477f59b", "5c6cfe79e05bd9007477f59c", "5c6cfe79e05bd9007477f5af", "5c6cfe79e05bd9007477f5b2",
"5c6cfe79e05bd9007477f5e5", "5c6cfe79e05bd9007477f66d", "5c6cfe79e05bd9007477f679"
]
}
},
},
{
"$match":
{ "date": { "$lte": ISODate("2019-02-13T12:32:02.000Z") } }
},
{"$match":
{ "date": { "$gte": ISODate("2019-02-11T12:32:02.000Z") } }
},
{
"$lookup":
{
"from": "agency",
"localField": "agency",
"foreignField": "_id",
"as": "agency"
}
},
{"$unwind": "$agency"},
{
"$lookup":
{
"from": "order",
"localField": "orders",
"foreignField": "_id",
"as": "orders"
}
},
{ "$unwind": "$orders" },
{
"$lookup":
{
"from": "driver",
"localField": "drivers",
"foreignField": "_id",
"as": "drivers"
}
},
{ "$unwind": "$drivers" },
{ "$unwind": "$camions" },
{
"$group": {
"_id": "$_id",
"orders": { "$addToSet": "$orders" },
"drivers": { "$last": "$drivers" },
"agency": { "$addToSet": "$agency" },
"type": { "$addToSet": "$type" },
"state": { "$addToSet": "$state" },
"date": { "$addToSet": "$date" }
}
},
{ "$unwind": "$agency" },
{ "$unwind": "$date" },
{ "$unwind": "$type" },
{ "$unwind": "$state" }
{
"$project":
{
"unloaded_orders": {
$filter: {
input: '$orders',
as: 'o',
cond: { $eq: ['$$o.state', 'unloaded'] }
}
},
"unclosed_orders": {
$filter: {
input: '$orders',
as: 'o',
cond: { $in: ['$$o.state', ['added', 'edited', 'started']] }
}
},
"closed_orders": {
$filter: {
input: '$orders',
as: 'o',
cond: { $eq: ['$$o.state', 'closed'] }
}
},
"agency": "$agency",
"date": "$date",
"state": "$state",
"type": "$type",
"drivers": "$drivers"
}
}
]);
Hope it could be help someone :)

Mongodb $lookup joins all collection instead of matching object

so I am trying to do a $lookup with Mongodb but I have a strange output.
I have two collections, "sites" and "consumptions".
sites :
{
"_id" : ObjectId("5b26db6e7f59e825909da106"),
"siteId" : 49,
"industry" : "Commercial Property",
"sub_industry" : "Shopping Center/Shopping Mall",
"square_feet" : 497092,
"latitude" : 41.2161756,
"longitude" : -78.14809154,
"timezone" : "America/New_York",
"timezone_offset" : "-04:00",
"__v" : 0
}
consumptions :
{
"_id" : ObjectId("5b26db907f59e825909f3d2a"),
"timestamp" : 1325382000,
"dttm_utc" : ISODate("2012-01-01T00:40:00Z"),
"value" : 2.8956,
"estimated" : 0,
"anomaly" : "",
"site" : [
{
"_id" : ObjectId("5b26db727f59e825909da16a")
}
],
"__v" : 0
}
This is the $lookup I am trying to do :
db.consumptions.aggregate([
{
$lookup:
{
from: "sites",
localField: "site.id",
foreignField: "id",
as: "site"
}
}
])
The expected output would be to have the detail of the site in each consumption :
{
"_id" : ObjectId("5b26db907f59e825909f3d2a"),
"timestamp" : 1325382000,
"dttm_utc" : ISODate("2012-01-01T00:40:00Z"),
"value" : 2.8956,
"estimated" : 0,
"anomaly" : "",
"site" : [
{
"_id" : ObjectId("5b26db6e7f59e825909da106"),
"siteId" : 49,
"industry" : "Commercial Property",
"sub_industry" : "Shopping Center/Shopping Mall",
"square_feet" : 497092,
"latitude" : 41.2161756,
"longitude" : -78.14809154,
"timezone" : "America/New_York",
"timezone_offset" : "-04:00",
"__v" : 0
}
],
"__v" : 0
}
This is the output I am getting with the $lookup :
{
"_id" : ObjectId("5b26db907f59e825909f3d2a"),
"timestamp" : 1325382000,
"dttm_utc" : ISODate("2012-01-01T00:40:00Z"),
"value" : 2.8956,
"estimated" : 0,
"anomaly" : "",
"site" : [
{
"_id" : ObjectId("5b26db6e7f59e825909da0f3"),
"siteId" : 6,
"industry" : "Commercial Property",
"sub_industry" : "Shopping Center/Shopping Mall",
"square_feet" : 161532,
"latitude" : 34.78300117,
"longitude" : -106.8952497,
"timezone" : "America/Denver",
"timezone_offset" : "-06:00",
"__v" : 0
},
{
"_id" : ObjectId("5b26db6e7f59e825909da0f4"),
"siteId" : 8,
"industry" : "Commercial Property",
"sub_industry" : "Shopping Center/Shopping Mall",
"square_feet" : 823966,
"latitude" : 40.32024733,
"longitude" : -76.40494239,
"timezone" : "America/New_York",
"timezone_offset" : "-04:00",
"__v" : 0
}, ... (all the sites details are listed)
],
"__v" : 0
}
Thank you in advance for your help !
You need to first $unwind the site array to match site._id to the foreign field _id and then $group to rolling back into the arrays again.
db.collection.aggregate([
{ "$unwind": "$site" },
{ "$lookup": {
"from": Site.collection.name,
"localField": "site._id",
"foreignField": "_id",
"as": "site"
}},
{ "$unwind": "$site" },
{ "$group": {
"_id": "$_id",
"value": { "$first": "$value" },
"estimated": { "$first": "$estimated" },
"anomaly": { "$first": "$anomaly" },
"timestamp": { "$first": "$timestamp" },
"dttm_utc": { "$first": "$dttm_utc" },
"site": { "$push": "$site" }
}}
])
And if you have mongodb 3.6 then you can try this
db.collection.aggregate([
{ "$unwind": "$site" },
{ "$lookup": {
"from": Site.collection.name,
"let": { "siteId": "$site._id" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$siteId" ] } } }
],
"as": "site"
}},
{ "$unwind": "$site" },
{ "$group": {
"_id": "$_id",
"value": { "$first": "$value" },
"estimated": { "$first": "$estimated" },
"anomaly": { "$first": "$anomaly" },
"timestamp": { "$first": "$timestamp" },
"dttm_utc": { "$first": "$dttm_utc" },
"site": { "$push": "$site" }
}}
])
Make sure you should put Site.collection.name correctly
I think that The $lookup doesn't work directly with an array.
try using $unwind first.

MongoDb aggregation query with $group and $push into subdocument

I have a question regarding the $group argument of MongoDb aggregations. My data structure looks as follows:
My "Event" collection contains this single document:
{
"_id": ObjectId("mongodbobjectid..."),
"name": "Some Event",
"attendeeContainer": {
"min": 0,
"max": 10,
"attendees": [
{
"type": 1,
"status": 2,
"contact": ObjectId("mongodbobjectidHEX1")
},
{
"type": 7,
"status": 4,
"contact": ObjectId("mongodbobjectidHEX2")
}
]
}
}
My "Contact" collection contains these documents:
{
"_id": ObjectId("mongodbobjectidHEX1"),
"name": "John Doe",
"age": 35
},
{
"_id": ObjectId("mongodbobjectidHEX2"),
"name": "Peter Pan",
"age": 60
}
What I want to do is perform an aggregate query on the "Event" collection and get the following result with full "contact" data:
{
"_id": ObjectId("mongodbobjectid..."),
"name": "Some Event",
"attendeeContainer": {
"min": 0,
"max": 10,
"attendees": [
{
"type": 1,
"status": 2,
"contact": {
"_id": ObjectId("mongodbobjectidHEX1"),
"name": "John Doe",
"age": 35
}
},
{
"type": 7,
"status": 4,
"contact": {
"_id": ObjectId("mongodbobjectidHEX2"),
"name": "Peter Pan",
"age": 60
}
}
]
}
}
The arguments I am using right now look as follows (shortened version):
"$unwind" : "$attendeeContainer.attendees",
"$lookup" : { "from" : "contactinfo", "localField" : "attendeeContainer.attendees.contact","foreignField" : "_id", "as" : "contactInfo" },
"$unwind" : "$contactInfo",
"$group" : { "_id": "$_id",
"name": { "$first" : "$name" },
...
"contact": { "$push": { "contact": "$contactInfo"} }
}
However, this leads to the "contact" array being on "Event" level (because of the grouping) instead of one document of the array being at each "attendeeContainer.attendees". How can I push the "contact" array to be at "attendeeContainer.attendees"? (as shown in the desired output above)
I tried things like:
"attendeeContainer.attendees.contact": { "$push": { "contact": "$contactInfo"} }
But mongodb apparently does not allow "." at $group stage.
Try running the following aggregation pipeline, the key is using a final $project pipeline to create the attendeeContainer subdocument:
db.event.aggregate([
{ "$unwind": "$attendeeContainer.attendees" },
{
"$lookup" : {
"from" : "contactinfo",
"localField" : "attendeeContainer.attendees.contact",
"foreignField" : "_id",
"as" : "attendeeContainer.attendees.contactInfo"
}
},
{ "$unwind": "$attendeeContainer.attendees.contactInfo" },
{
"$group": {
"_id" : "$_id",
"name": { "$first": "$name" },
"min" : { "$first": "$attendeeContainer.min" },
"max" : { "$first": "$attendeeContainer.max" },
"attendees": { "$push": "$attendeeContainer.attendees" }
}
},
{
"$project": {
"name": 1,
"attendeeContainer.min": "$min",
"attendeeContainer.max": "$min",
"attendeeContainer.attendees": "$attendees"
}
}
])
Debugging Tips
Debugging the pipeline at the 4th stage, you would get the result
db.event.aggregate([
{ "$unwind": "$attendeeContainer.attendees" },
{
"$lookup" : {
"from" : "contactinfo",
"localField" : "attendeeContainer.attendees.contact",
"foreignField" : "_id",
"as" : "attendeeContainer.attendees.contactInfo"
}
},
{ "$unwind": "$attendeeContainer.attendees.contactInfo" },
{
"$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"min" : { "$first": "$attendeeContainer.min" },
"max" : { "$first": "$attendeeContainer.max" },
"attendees": { "$push": "$attendeeContainer.attendees" }
}
}/*,
{
"$project": {
"name": 1,
"attendeeContainer.min": "$min",
"attendeeContainer.max": "$min",
"attendeeContainer.attendees": "$attendees"
}
}*/
])
Pipeline result
{
"_id" : ObjectId("582c789282a9183adc0b53f5"),
"name" : "Some Event",
"min" : 0,
"max" : 10,
"attendees" : [
{
"type" : 1,
"status" : 2,
"contact" : ObjectId("582c787682a9183adc0b53f3"),
"contactInfo" : {
"_id" : ObjectId("582c787682a9183adc0b53f3"),
"name" : "John Doe",
"age" : 35
}
},
{
"type" : 7,
"status" : 4,
"contact" : ObjectId("582c787682a9183adc0b53f4"),
"contactInfo" : {
"_id" : ObjectId("582c787682a9183adc0b53f4"),
"name" : "Peter Pan",
"age" : 60
}
}
]
}
and the final $project pipeline will give you the desired result:
db.event.aggregate([
{ "$unwind": "$attendeeContainer.attendees" },
{
"$lookup" : {
"from" : "contactinfo",
"localField" : "attendeeContainer.attendees.contact",
"foreignField" : "_id",
"as" : "attendeeContainer.attendees.contactInfo"
}
},
{ "$unwind": "$attendeeContainer.attendees.contactInfo" },
{
"$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"min" : { "$first": "$attendeeContainer.min" },
"max" : { "$first": "$attendeeContainer.max" },
"attendees": { "$push": "$attendeeContainer.attendees" }
}
},
{
"$project": {
"name": 1,
"attendeeContainer.min": "$min",
"attendeeContainer.max": "$min",
"attendeeContainer.attendees": "$attendees"
}
}/**/
])
Desired/Actual Output
{
"_id" : ObjectId("582c789282a9183adc0b53f5"),
"name" : "Some Event",
"attendeeContainer" : {
"min" : 0,
"max" : 10,
"attendees" : [
{
"type" : 1,
"status" : 2,
"contact" : ObjectId("582c787682a9183adc0b53f3"),
"contactInfo" : {
"_id" : ObjectId("582c787682a9183adc0b53f3"),
"name" : "John Doe",
"age" : 35
}
},
{
"type" : 7,
"status" : 4,
"contact" : ObjectId("582c787682a9183adc0b53f4"),
"contactInfo" : {
"_id" : ObjectId("582c787682a9183adc0b53f4"),
"name" : "Peter Pan",
"age" : 60
}
}
]
}
}