Lookup on array of ids mongodb - 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 :)

Related

Merge mongodb aggregation results of unread messages count per conversation member into document

I want to aggregate unread messages count per member in a conversation group and seems my aggregation pipeline is working correctly, but, I don't know how to achieve the following results.
Please check the example.
Thread documents
/* 1 */
{
"_id" : ObjectId("60d4efa6a95f446051f31492"),
"latestMessage" : "Voluptatem eos officiis optio dolor est et.",
"type" : "FEED",
"users" : [
{
"_id" : ObjectId("60d4efa6a95f446051f31491"),
"displayName" : "Monique Connelly II"
},
{
"_id" : ObjectId("60d4efa6a95f446051f31490"),
"displayName" : "Ivory Jacobson DDS"
},
{
"_id" : ObjectId("60d4efa6a95f446051f3148f"),
"displayName" : "Ron Weimann"
}
],
"createdBy" : "60d4efa6a95f446051f3148f",
"createdAt" : ISODate("2021-06-24T20:48:38.537Z"),
"modifiedAt" : ISODate("2021-06-24T20:48:38.620Z"),
}
/* 2 */
{
"_id" : ObjectId("60d4efa6a95f446051f31493"),
"type" : "CONVERSATION",
"users" : [
{
"_id" : ObjectId("60d4efa6a95f446051f31491"),
"displayName" : "Monique Connelly II"
},
{
"_id" : ObjectId("60d4efa6a95f446051f31490"),
"displayName" : "Ivory Jacobson DDS"
},
{
"_id" : ObjectId("60d4efa6a95f446051f3148f"),
"displayName" : "Ron Weimann"
}
],
"createdBy" : "60d4efa6a95f446051f3148f",
"createdAt" : ISODate("2021-06-24T20:48:38.569Z"),
"modifiedAt" : ISODate("2021-06-24T20:48:38.569Z"),
}
Message documents
/* 1 */
{
"_id" : ObjectId("60d4efa6a95f446051f31494"),
"content" : "Itaque rerum facere neque fuga aspernatur dolorum.",
"deleted" : false,
"threadId" : ObjectId("60d4efa6a95f446051f31492"),
"type" : "TEXT",
"thread" : {
"$ref" : "threads",
"$id" : ObjectId("60d4efa6a95f446051f31492")
},
"readBy" : [
ObjectId("60d4efa6a95f446051f3148f")
],
"attributes" : [],
"createdBy" : "60d4efa6a95f446051f3148f",
"createdAt" : ISODate("2021-06-24T20:48:38.598Z"),
"modifiedAt" : ISODate("2021-06-24T20:48:38.598Z"),
}
/* 2 */
{
"_id" : ObjectId("60d4efa6a95f446051f31495"),
"content" : "Nisi suscipit iste magni voluptatem.",
"deleted" : false,
"threadId" : ObjectId("60d4efa6a95f446051f31492"),
"type" : "TEXT",
"thread" : {
"$ref" : "threads",
"$id" : ObjectId("60d4efa6a95f446051f31492")
},
"readBy" : [
ObjectId("60d4efa6a95f446051f3148f")
],
"attributes" : [],
"createdBy" : "60d4efa6a95f446051f3148f",
"createdAt" : ISODate("2021-06-24T20:48:38.610Z"),
"modifiedAt" : ISODate("2021-06-24T20:48:38.610Z"),
}
and more...
My aggregation pipeline
db.threads.aggregate([
{ "$lookup": { "from": "messages", "localField": "_id", "foreignField": "threadId", "as": "message"}},
{ "$unwind": "$message" },
{ "$unwind": "$users" },
{ "$unwind": "$message.readBy" },
{ "$group": {
"_id": {
"user_id": "$users._id",
"thread_id": "$_id",
},
"unread_messages": {
"$sum": {
"$cond": [
{ "$ne": [ "$users._id", "$message.readBy" ] },
1,
0
]
}
}
}},
// { "$replaceRoot": { "newRoot": { "$mergeObjects": ["$_id", { "count": "$unread_messages" }]} } }
])
Aggregation results
{
"_id" : {
"user_id" : ObjectId("60d4efa6a95f446051f31491"),
"thread_id" : ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages" : 4.0
},
{
"_id" : {
"user_id" : ObjectId("60d4efa6a95f446051f3148f"),
"thread_id" : ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages" : 4.0
},
{
"_id" : {
"user_id" : ObjectId("60d4efa6a95f446051f31490"),
"thread_id" : ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages" : 4.0
}
Results are partially OK, but, I want to keep my original structure of a document and copy aggregation results accordingly to the thread id back to the original document
I would be very grateful if you help me with the aggregation pipeline
Expected results
{
"_id": ObjectId("60d4efa6a95f446051f31492"),
"latestMessage": "Voluptatem eos officiis optio dolor est et.",
"type": "LISTING",
"users": [{
"_id": ObjectId("60d4efa6a95f446051f31491"),
"displayName": "Monique Connelly II"
},
{
"_id": ObjectId("60d4efa6a95f446051f31490"),
"displayName": "Ivory Jacobson DDS"
},
{
"_id": ObjectId("60d4efa6a95f446051f3148f"),
"displayName": "Ron Weimann"
}
],
"createdBy": "60d4efa6a95f446051f3148f",
"createdAt": ISODate("2021-06-24T20:48:38.537Z"),
"modifiedAt": ISODate("2021-06-24T20:48:38.620Z"),
"message": [...],
"stats": [{
"_id": {
"user_id": ObjectId("60d4efa6a95f446051f31491"),
"thread_id": ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages": 4.0
},
{
"_id": {
"user_id": ObjectId("60d4efa6a95f446051f3148f"),
"thread_id": ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages": 4.0
},
{
"_id": {
"user_id": ObjectId("60d4efa6a95f446051f31490"),
"thread_id": ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages": 4.0
}
]
}
I post a solution that works perfectly for my case with $first + $replateRoot operations.
Final results have different ids as not in the first post that is because I re-created documents
db.threads.aggregate([
{ "$lookup": { "from": "messages", "localField": "_id", "foreignField": "threadId", "as": "message"}},
{ "$unwind": "$message" },
{ "$unwind": "$users" },
{ "$unwind": "$message.readBy" },
{ "$group": {
"_id": {
"user_id": "$users._id",
"thread_id": "$_id",
},
"thread": {
"$first": "$$ROOT"
},
"unread_messages": {
"$sum": {
"$cond": [
{ "$ne": [ "$users._id", "$message.readBy" ] },
1,
0
]
}
}
}},
{ "$group": {
"_id": "$_id.thread_id",
"thread": { "$first": "$thread" },
"stats": {
"$push": {
"userId": "$_id.user_id",
"unreadMessages": "$unread_messages"
}
}
}},
{ "$replaceRoot": { "newRoot": { "$mergeObjects": ["$thread", { stats: "$stats" }]} } }
])
Final results
/* 1 */
{
"_id" : ObjectId("60d574e242e59a48b886c586"),
"latestMessage" : "Molestias quo quod occaecati exercitationem veniam eaque.",
"type" : "LISTING",
"users" : {
"_id" : ObjectId("60d574e242e59a48b886c584"),
"displayName" : "Meggan Vandervort"
},
"unreadMessages" : NumberLong(0),
"createdBy" : "60d574e242e59a48b886c582",
"createdAt" : ISODate("2021-06-25T06:17:06.547Z"),
"modifiedAt" : ISODate("2021-06-25T06:17:06.617Z")
"message" : {
"_id" : ObjectId("60d574e242e59a48b886c58d"),
"content" : "Velit dolores vel.",
"deleted" : false,
"threadId" : ObjectId("60d574e242e59a48b886c586"),
"type" : "TEXT",
"thread" : {
"$ref" : "threads",
"$id" : ObjectId("60d574e242e59a48b886c586")
},
"readBy" : ObjectId("60d574e242e59a48b886c582"),
"attributes" : [],
"createdBy" : "60d574e242e59a48b886c582",
"createdAt" : ISODate("2021-06-25T06:17:06.595Z"),
"modifiedAt" : ISODate("2021-06-25T06:17:06.595Z")
},
"stats" : [
{
"userId" : ObjectId("60d574e242e59a48b886c584"),
"unreadessages" : 6.0
},
{
"userId" : ObjectId("60d574e242e59a48b886c583"),
"unreadessages" : 6.0
},
{
"userId" : ObjectId("60d574e242e59a48b886c582"),
"unreadessages" : 6.0
}
]
}
and more...

mongodb aggregate function and return the result based on the condition

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"},
}
}
])

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"
}
]

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 retrieving document from inside of document

I have problems with MongoDB's aggregation.
In my "Job" document, it has creatorParent(single value) and Children(array of mongodb object id). In the "User" document, user has children array with child details.
When user request for retrieving this document I want aggregate child details, if array contains id of child.
I wrote an aggregation with some help, It worked for creatorParent but whatever I've tried, it didn't worked for children.
db.getCollection('Jobs').aggregate([
{
$unwind: {
path : "$children"
}
},
{
$lookup: {
"from" : "Users",
"localField" : "creatorparent",
"foreignField" : "_id",
"as" : "creatorparent"
}
},
{
$lookup: {
"from" : "Users",
"localField" : "children",
"foreignField" : "children",
"as" : "children"
}
}
])
Users document:
{
"_id" : ObjectId("58daf84877733645eaa9b44f"),
"email" : "meto93#gmail.com",
"password" : "vpGl+Fjnef616cRgNbCkwaFDpSI=",
"passwordsalt" : "99397F4A9D3A499D96694547667E74595CE994D2E83345D6953EF866303E8B65",
"children" : [
{
"_id" : ObjectId("58daf84977733645eaa9b450"),
"name" : "Mert",
"age" : 5,
"additionalinformation" : "ilk cocuk",
"creationtime" : ISODate("2017-03-28T23:56:56.952Z"),
"userid" : ObjectId("58daf84877733645eaa9b44f"),
"gender" : null
},
{
"_id" : ObjectId("58daf84977733645eaa9b451"),
"name" : "Sencer",
"age" : 7,
"additionalinformation" : "ikinci cocuk",
"creationtime" : ISODate("2017-03-28T23:56:56.952Z"),
"userid" : ObjectId("58daf84877733645eaa9b44f"),
"gender" : null
}
]
}
Job
{
"_id" : ObjectId("58db0a2d77733645eaa9b453"),
"creationtime" : ISODate("2017-03-29T01:13:17.509Z"),
"startingtime" : ISODate("2017-04-03T13:00:00.000Z"),
"endingtime" : ISODate("2017-04-03T17:00:00.000Z"),
"children" : [
ObjectId("58daf84977733645eaa9b450"),
ObjectId("58daf84977733645eaa9b451")
],
"creatorparent" : ObjectId("58daf84877733645eaa9b44f"),
"applicants" : []
}
Try this:
db.jobs.aggregate(
[
{
$unwind: {
path : "$children",
}
},
{
$lookup: {
"from" : "users",
"localField" : "creatorparent",
"foreignField" : "_id",
"as" : "creatorparent"
}
},
{
$lookup: {
"from" : "users",
"localField" : "children",
"foreignField" : "children._id",
"as" : "children"
}
},
{
$addFields: {
children : {$arrayElemAt : ["$children",0]}
}
},
{
$addFields: {
"children":"$children.children"
}
},
{
$unwind: {
path : "$children",
}
},
{
$group: {
"_id": "$_id",
"name": { "$first": "$name" },
"jobstatus" : { "$first": "$jobstatus" },
"hourlyrate" : { "$first": "$hourlyrate" },
"creatorparent" : { "$first" : "$creatorparent" },
"children": { "$addToSet": "$children" }
}
},
]
);