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"
}
}
]);
Related
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
}
}])
I have an aggregate query where I join 3 collections. I'd like to filter the search based on fields from two of those collections. The problem is, I'm only able to use $match on the initial collection that mongoose initialized with.
Here's the query:
var pipeline = [
{
$lookup: {
from: 'blurts',
localField: 'followee',
foreignField: 'author.id',
as: 'followerBlurts'
}
},
{
$unwind: '$followerBlurts'
},
{
$lookup: {
from: 'users',
localField: 'followee',
foreignField: '_id',
as: 'usertbl'
}
},
{
$unwind: '$usertbl'
},
{
$match: {
'follower': { $eq: req.user._id },
//'blurtDate': { $gte: qryDateFrom, $lte: qryDateTo }
}
},
{
$sample: { 'size': 42 }
},
{
$project: {
_id: '$followerBlurts._id',
name: '$usertbl.name',
smImg: '$usertbl.smImg',
text: '$followerBlurts.text',
vote: '$followerBlurts.vote',
blurtDate: '$followerBlurts.blurtDate',
blurtImg: '$followerBlurts.blurtImg'
}
}
];
keystone.list('Follow').model.aggregate(pipeline)
.sort({blurtDate: -1})
.cursor().exec()
.toArray(function(err, data) {
if (!err) {
res.json(data);
} else {
console.log('Error getting following blurts --> ' + err);
}
});
Within the pipeline, I can only use $match on the 'Follow' model. When I use $match on the 'Blurt' model, it simply ignores the condition (you can see where I tried to include it in the commented line under $match).
What's perplexing is that I can utilize this field in the .sort method, but not in the $match conditions.
Any help much appreciated.
You can use the mongo dot notation to access elements of the collection that is being looked up via $lookup.
https://docs.mongodb.com/manual/core/document/#dot-notation
So, in this case followerBlurts.blurtDate should give you the value you are looking for.
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
I'm fairly new to MongoDB and need help doing a select, or perhaps some sort of left join, on one collection based on another collection's data.
I have two collections, animals and meals, and I want to get the animal(s) that has had it's last registered meal after a certain date (let's say 20171001) to determine if the animal is still active.
collection animals:
{
name: mr floof,
id: 12345,
lastMeal: abcdef
},
{
name: pluto,
id: 6789,
lastMeal: ghijkl
}
collection meals:
{
id: abcdef,
created: 20171008,
name: carrots
},
{
id: ghijkl,
created: 20170918,
name: lettuce
}
So the expected output of the query in this case would be:
{
name: mr floof,
id: 12345,
lastMeal: abcdef
}
As Mr Floof has had his last meal 20171008, i.e. after 20171001.
Hope I was clear enough, but if not, don't hesitate to ask.
You can try below aggregation query.
db.animals.aggregate([ [
{
"$lookup": {
"from": "meals",
"localField": "lastMeal",
"foreignField": "id",
"as": "last_meal"
}
},
{
"$unwind": "$last_meal"
},
{
"$match": {
"last_meal.created": {
"$gt": 20171001
}
}
}
])
More info here.
You can use $project with exclusion after $match stage to format the response to exclude joined fields. Something like { $project: {"last_meal":0} }
MongoDB supports joins with $lookup , In your case you can use query like:-
db.animals.aggregate([
{
$lookup:
{
from: "meals",
localField: "lastMeal",
foreignField: "id",
as: "last_meal"
}
},
{
$match: {
"created" : {
$gt: "date" //your date format
}
}
}
])
thanks !
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.