Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongodb aggregate with $group and $lookup

I'm trying to perform a "group by" on a table and "join" it with another table. Corresponding SQL statement would be:

SELECT T1.total, T1.email, T1.type, table_2.name FROM
(SELECT SUM(amount) AS total, email, type 
FROM table_1
GROUP BY email, type) T1
INNER JOIN table_2
on T1.email = table_2.email 

But since mongodb still doesn't have inner join feature, I tried to use "$lookup" and do the task. here's my code:

db.table_1.aggregate([
{$group : {_id : {email: "$email", type:"$type"},total: { $sum: "$amount" }}},
{$lookup: {from: "table_2", localField: "email", foreignField: "email", as: "details"}} ]);

But in the results I'm getting, details returns and empty object:

{ "_id" : { "user" : "[email protected]", "type" : "Car" }, "total" : 2, "details" : [ ] }
{ "_id" : { "user" : "[email protected]", "type" : "Bike" }, "total" : 3, "details" : [ ] }
{ "_id" : { "user" : "[email protected]", "type" : "Car" }, "total" : 1, "details" : [ ] }

But if I run the query without using $group, it works fine. So I'm wondering whether the $group and $lookup functions cannot be used together. If so is there a work-around or what would be the optimal way to get the query done?

[mongo db version I'm using: > db.version() 3.2.7]

like image 556
KTB Avatar asked Aug 23 '16 03:08

KTB


People also ask

Is it possible to do a $lookup aggregation between two databases in MongoDB?

We can join documents on collections in MongoDB by using the $lookup (Aggregation) function. $lookup(Aggregation) creates an outer left join with another collection and helps to filter data from merged data.

Can we join 2 collections in MongoDB?

MongoDB JOIN operation with two collections is performed by the use of $lookup operator developed having version 3.2. The $lookup operator proceeds a document having the below fields: From: It states the collection within the identical database for executing the join with but with Sharded Collection Restrictions.

What is the purpose of the $group operator in an aggregate pipeline?

The $group stage groups the documents by date and calculates the total sale amount, average quantity, and total count of the documents in each group.


2 Answers

I found the answer to the problem. The reason why I got empty array was the way I've used the localField inside the $lookup.

Since I'm trying to join the table_2 with the $group result of the table_1, the local field should be "_id.email".

So the working query would be:

db.table_1.aggregate([
    {$group : {_id : {email: "$email", type:"$type"},total: { $sum: "$amount" }}},
    {$lookup: {from: "table_2", localField: "_id.email", foreignField: "email", as: "details"}},
    {$match: {details: {$ne: []}}}
]);

Thanks @Wake and @Clement for help

like image 134
KTB Avatar answered Oct 18 '22 10:10

KTB


If you want your $lookup to work like an INNER JOIN, that is, you don't want results unless there is at least one matching document in the lookup table, you can add a $match at the end comparing your lookup table results to an empty array [ ]:

db.table_1.aggregate([
    {$group : {_id : {email: "$email", type:"$type"},total: { $sum: "$amount" }}},
    {$lookup: {from: "table_2", localField: "email", foreignField: "email", as: "details"}},
    {$match: {details: {$ne: []}}}
]);
like image 33
Wake Avatar answered Oct 18 '22 09:10

Wake