mongodb 2 level aggregation [duplicate] - mongodb

This question already has answers here:
MongoDB nested lookup with 3 levels
(2 answers)
Closed 2 years ago.
I have 3 collections that are referred to each other such that
A -> B -> C
I want to filter data after matching that with B and from B to C
Collection 1
Products: [{
_id:ObjectId(),
name:"product1",
productCatalogue:[reference to productCatalogue collection]
},....]
Collection 2
productCatalogue: [{
_id:ObjectId(),
name:"catelgoue1",
category:{
cat:[reference to category table],
sub1:[reference to category table],
sub2:[reference to category table]
}
},...]
Collection 3
category: [{
_id:ObjectId(),
name:"cat1",
type:"parent"
},....]
I want to filter data such that products having catalog:catelgoue1 and category: cat1 will be filtered using aggregation.

you can using before every lookup for $match
example code:
const orderProcess = await Order.aggregate([
{
$match: {
userId: userId
}
},
{
$lookup: {
from: "products",
localField: "product_id",
foreignField: "_id",
as: "product",
}
},
{
$unwind: "$product"
},
{
$lookup: {
from: "prices",
localField: "product_id", // $product._id => like top lookup data
foreignField: "productId", // $product._id => like top lookup data
as: "price"
},
},
{
$unwind: "$price"
},
{
$project:{
// response all item
}
}])

Related

How can I limit data using aggregate functions using mongoDB?

I'm trying to get the last data inserted in my collection using MongoDB. This is my code:
dht11.aggregate(
[
{
$lookup:
{
from: "storage_rooms",
localField: "node",
foreignField: "name",
as: "MainStorage"
}
},
{ $unwind: "$MainStorage"},
{ $match: {node: "Main Storage"} },
]
).sort({$natural:-1}).limit(1);

How to get left join data using multiple condition in mongodb

I have two table
master_document_table document_table
id | title id | master_document_id | userId
1 | Profile
select * from master_document_table as md
left join document_table as d on md.id = d.master_document_id and d.userId = 2
Result:
id | title | master_document_id | userId
1 | Profile null null
how can this be achieved using mongodb i have tried & also did some research from stack overflow and did not got the expected result.
From mongo v3.2, it is possible to aggregate two or more than two collections.
But here one thing, you need to know is, you won't get the same structure as sql. You will get your data on nested document.
Your tables will look something like this in mongodb:
master_document_table (collection / table)
{
_id: ObjectId("5f28d53c00613e6ada45f702"),
title: "Profile",
}
document_table (collection / table)
{
_id: ObjectId("5f28d53c00613e6ada45e790"),
master_document_id: ObjectId("5f28d53c00613e6ada45f702"), // master_doc_table's ref id.
userId: ObjectId("5f28d53c00613e6ada327f231"), // user's ref id.
}
Your query will be:
db.document_table.aggregate([
{$match: {title: "Profile"}}, // you can give any condition here.
{
$lookup:
{
from: "master_document_table",
localField: "master_document_id",
foreignField: "_id",
as: "master_document_id"
}
}
])
Your query result will look something like:
[{
_id: ObjectId("5f28d53c00613e6ada45e790"),
master_document_id: {
_id: ObjectId("5f28d53c00613e6ada45f702"),
title: "Profile"
},
userId: ObjectId("5f28d53c00613e6ada327f231"),
}]
Now you can restructure it based on your requirement.
I would like to recommend you
https://docs.mongodb.com/manual/reference/operator/aggregation/match/
&
https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/
article from mongodb docs.
Hope this will help to resolve your problem.
Inorder to join two tables you can use the $lookup aggregation pipeline operator in version 3.6 and newer. Since you need the results like LEFT OUTER JOIN, you have to $unwind the array to objects and filter out the desired results using $match conditions (ie document_table.userId = 2). Dont forget to use preserveNullAndEmptyArrays to true when unwinding.
Sample code for reference:
db.master_document_table.aggregate([
{ "$lookup": {
"from": "document_table",
"localField": "id",
"foreignField": "master_document_id",
"as": "document_table"
}},
{ $unwind: { path: "$document_table", preserveNullAndEmptyArrays: true } },
{
$match:{
$or:[
{ "document_table": { $exists: false } },
{"document_table.userId" : 2 }
]
}
}
])
I some how managed to get desire result thanks for the help
db.master_document_table.aggregate([
{
$lookup: {
from: 'document_table',
localField: 'id',
foreignField: 'master_document_id',
as: 'users'
}
},
{
$project: {
title: 1,
users: {
$filter: {
input: '$users',
as: 'user',
cond: {
$eq: ['$$user.userId', 2]
}
}
}
}
}
]);

MongoDB aggregate $lookup to return unmatched items from the main collection

I would like unmatched data from the USERS collection. Here I have two collections 1) USERS, 2) COMPANY.I am able to get the matched data from both USERS using aggregate function. but in this case I want data from USERS table which are not assigned to a company.
USERS table
{
_id: "AAA",
fullName:"John Papa"
},
{
_id: "BBB",
fullName:"Robin Son"
}
COMPANY table
{
_id: "1sd1s",
Name:"Lumbar Company"
User:"AAA"
},
{
_id: "23s1dfs3",
Name:"Patricia"
User:"AAA"
}
$lookup works like LEFT OUTER JOIN so it will remove empty array when there's no match. Then you can use $size to get only empty arrays:
db.users.aggregate([
{
$lookup: {
from: "company",
localField: "_id",
foreignField: "User",
as: "companies"
}
},
{
$match: {
$expr: {
$eq: [ { "$size": "$companies" }, 0 ]
}
}
}
])
Mongo Playground

How to use aggregation single query for array and array in side array for get details from mongodb ?

I want to use aggregation query in three table on mongodb,
I listed three table that store db data, and i send you query that i used,
but output not getting that i want.
Order Table
In Order Table I have one create order and in that Object "Order Details"
"order_details":[
{
"product_unique_id" : 10
"items":[
{
"item_unique_id" : 1
"quantity":2,
},
{
"item_unique_id" : 2
"quantity":4,
}
]
},
{
"product_unique_id" : 11
"items":[
{
"item_unique_id" : 1
"quantity":1,
},
{
"item_unique_id" : 3
"quantity":3,
},
{
"item_unique_id" : 4
"quantity":2,
}
]
}
]
Product Table
Data 1 => {"unique_id":10, "product_name":"Product10", "product_visible":true}
Data 2 => {"unique_id":11, "product_name":"Product11", "product_visible":false}
Data 3 => {"unique_id":12, "product_name":"Product13", "product_visible":true}
... up to N
Item Table
Data 1 => {"unique_id":1, "item_name":"Item1", "price":17}
Data 2 => {"unique_id":2, "item_name":"Item2", "price":9}
Data 3 => {"unique_id":3, "item_name":"Item3", "price":34}
Data 4 => {"unique_id":4, "item_name":"Item4", "price":78}
Data 5 => {"unique_id":5, "item_name":"Item5", "price":26}
I want to run aggregation query in order table and want response as below
OUTPUT I WANT IS
"order_details":[
{
"product_unique_id" : 10,
"product_detail": {"unique_id":10, "product_name":"Product10", "product_visible":true},
"items":[
{
"item_unique_id" : 1
"quantity":2,
"item_details":{"unique_id":1, "item_name":"Item1", "price":17}
},
{
"item_unique_id" : 2
"quantity":4,
"item_details":{"unique_id":2, "item_name":"Item2", "price":9}
}
]
},
{
"product_unique_id" : 11,
"product_detail": {"unique_id":11, "product_name":"Product11", "product_visible":false},
"items":[
{
"item_unique_id" : 1
"quantity":1,
"item_details":{"unique_id":1, "item_name":"Item1", "price":17}
},
{
"item_unique_id" : 3
"quantity":3,
"item_details":{"unique_id":3, "item_name":"Item3", "price":34}
},
{
"item_unique_id" : 4
"quantity":2,
"item_details":{"unique_id":4, "item_name":"Item4", "price":78}
}
]
}
]
I USED SOME QUERY FOR THAT BUT OUT PUT COMING WITH MULTIPLE ITEMS
var product_query = {
$lookup:
{
from: "products",
localField: "order_details.product_unique_id",
foreignField: "unique_id",
as: "order_details.product_detail"
}
};
var group_product = {
$group: {
_id: '$order_details'
}
}
var item_query = {
$lookup:
{
from: "items",
localField: "order_details.items.item_unique_id",
foreignField: "unique_id",
as: "order_details.item_details"
}
};
Order.aggregate([
{$unwind: "$order_details"},
{$unwind: "$order_details.items"},
product_query,
item_query,
group_product
], function (error, order) {
// OUT PUT HERE
});
You can try below aggregation pipeline. I'm assuming you are on 3.2 version.
Pretty standard stuff. You'll need to $unwind + $lookup + $group couple of times each for items and products and rest is formatting the response to put everything back into the original structure.
db.orders.aggregate([
{$unwind: "$order_details"},
{$unwind: "$order_details.items"},
{$lookup:{
from: "items",
localField: "order_details.items.item_unique_id",
foreignField: "unique_id",
as: "order_details.items.item_details"
}
},
{$unwind: "$order_details.items.item_details"},
{ $group: {
_id: {order_id:'$_id', product_unique_id:"$order_details.product_unique_id"},
"items": {$push:"$order_details.items"}
}
},
{$lookup:{
from: "products",
localField: "_id.product_unique_id",
foreignField: "unique_id",
as: "_id.product_detail"
}
},
{$unwind: "$_id.product_detail"},
{$project:{
"order_detail.product_unique_id":"$_id.product_unique_id",
"order_detail.product_detail":"$_id.product_detail",
"order_detail.items":"$items"
}
},
{$group: {
_id: '$_id.order_id', order_details:{$push:"$order_detail"}
}
}
])
This pipeline can further be improved for 3.4 version. I can add extra edits if you need for 3.4 version.

mongodb join multiple collections [duplicate]

This question already has answers here:
Multiple join conditions using the $lookup operator
(4 answers)
Closed 5 years ago.
I'd like to "join" 3 Collections in MongoDB by using mongochef. The collections are "Order", "Employee" and "City". I tried to use temp collections, but it is not effective.
Now I am using var = a for the first "join".
If I 'd like to show "a", there are displayed 20 results only.
Do you have an idea or another solution?
var a = db.Order.aggregate([
{
$lookup:
{
from: "City",
localField: "City Key",
foreignField: "City Key",
as: "lsg"
}
},
{
$unwind: "$lsg"
},
{
$project:
{
"_id":1,
"Salesperson Key":1,
"City": "$lsg.City"
}
}
])
a;
var b = db.Employee.aggregate([
{
$lookup:
{
from: "a",
localField: "Employee Key",
foreignField: "Salesperson Key",
as: "lsg2"
}
},
{
$unwind: "$lsg2"
},
{
$project:
{
"_id":1,
"Employee":1
}
}
])
Thanks in advance for replies.
you can put multiple $lookup stages, so you could use a query like this (could't test it but should work)
But you should avoid multiple joins, keep in mind that MongoDB is not a relational database...
db.Order.aggregate([
{
$lookup:{
from:"City",
localField:"City Key",
foreignField:"City Key",
as:"lsg"
}
},
{
$unwind:"$lsg"
},
{
$lookup:{
from:"Employee",
localField:"Salesperson Key",
foreignField:"Employee Key",
as:"lsg2"
}
},
{
$unwind:"$lsg2"
},
{
$project:{
"_id":1,
"Employee":1,
"Salesperson Key":1,
"City":"$lsg.City"
}
}
]);