MongoDB aggregating data - mongodb

when I am running code from Mongodb docs to use pipeline in the $lookup
I am getting an error that let is not supported. How to use let: { <var_1>: , …, <var_n>: } inside of $lookup.
Error:
Code:
db.orders.aggregate([
{
$lookup:
{
from: "warehouses",
let: { order_item: "$item", order_qty: "$ordered" },
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$stock_item", "$$order_item" ] },
{ $gte: [ "$instock", "$$order_qty" ] }
]
}
}
},
{ $project: { stock_item: 0, _id: 0 } }
],
as: "stockdata"
}
}
])

Related

mongodb - Multiple LET and AS assignments to use within the same pipeline

How to perform multiple let and as and use them within the same pipeline. I have the following query but assignment defaults to userTo. Both userFrom and userTo are from users collection
{
$lookup: {
from: "users",
let: {
userFrom: "$from",
},
as: "userFrom",
let: {
userTo: "$to",
},
as: "userTo",
pipeline: [
{
$match: {
$expr: {
$or: [
{
$eq: [
"$$userFrom",
"$_id"
]
},
{
$eq: [
"$$userTo",
"$_id"
]
}
]
}
}
},
You are not using them correctly. as specifies the name of the output array of the $lookup. There is only 1 result set per lookup so only 1 as would be needed.
let specifies the variables you want to use in the sub-pipeline. You can put them in an object if you want to use multiple variables.
Your code should look like this:
db.collection.aggregate([
{
$lookup: {
from: "users",
let: {
userFrom: "$from",
userTo: "$to"
},
pipeline: [
{
$match: {
$expr: {
$or: [
{
$eq: [
"$$userFrom",
"$_id"
]
},
{
$eq: [
"$$userTo",
"$_id"
]
}
]
}
}
}
],
as: "userLookup"
}
}
])

Mongo Db How to detect error in pipeline?

I need to join two collection with two conditions.
products:
{
...
sku: "4234",
organizationId: ObjectId("asdasdasd);
...
};
order_history:
{
...
itemSku: "4234",
organizationId: ObjectId("asdasdasd);
...
}
I chose pipeline approach:
$lookup: {
from: 'order_history',
let: { foreign_sku: "$itemSku", foreign_organizationId: "$organizationId" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ["$organizationId", "$$foreign_organizationId"] },
{ $eq: ["$sku", "$$foreign_sku" ] }
]
}
}
}
],
as: 'order_history'
}
I wrote it on base of Mongo Documentation, but my conditions are ignored.
I have scalar multiplication in result. Where is my mistake?
I already mention in the comment and the code is below
db.products.aggregate([
{
$lookup: {
from: "order_history",
let: {
foreign_sku: "$sku",
foreign_organizationId: "$organizationId"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$organizationId",
"$$foreign_organizationId"
]
},
{
$eq: [
"$itemSku",
"$$foreign_sku"
]
}
]
}
}
}
],
as: "order_history"
}
}
])
Working Mongo playground

Mongo db - How to get two counts from same collection with a single lookup?

I have a working query below:
{
$lookup: {
from: "watchList",
as: "watchList",
let: {
postId: "$_id",
userId: userCurrent
},
pipeline: [
{
$match: {
$and: [
{ $expr: {$eq: ["$postId","$$postId"]} },
{ $expr: {$eq: ["$$userId", "$user"]} },
]
}
},
{
$count: "watchCount"
},
]
}
},
The above query gives me a count of two conditions combined in AND:
{ $expr: {$eq: ["$postId","$$postId"]} },
{ $expr: {$eq: ["$$userId", "$user"]} },
In addition, is it possible to get the count of ONLY { $expr: {$eq: ["$postId","$$postId"]} } without doing another lookup ?
So there will be two counts -
Count 1:
AND condition for
{ $expr: {$eq: ["$postId","$$postId"]} },
{ $expr: {$eq: ["$$userId", "$user"]} },
Count 2:
Single condition
{ $expr: {$eq: ["$postId","$$postId"]} }
You can do something like this,
$group first match count to firstCount and second match count to secondCount
{
$lookup: {
from: "watchList",
as: "watchList",
let: {
postId: "$_id",
userId: userCurrent
},
pipeline: [
{
$group: {
_id: null,
firstCount: {
$sum: {
$cond: [
{
$and: [
{ $eq: ["$postId", "$$postId"] },
{ $eq: ["$$userId", "$user"] }
]
},
1,
0
]
}
},
secondCount: {
$sum: {
$cond: [{ $eq: ["$postId", "$$postId"] }, 1, 0]
}
}
}
}
]
}
}

how to reduce unnecessary unwind stages from aggregation pipeline

Like if i'm applying many lookup stages in aggregation pipeline and each lookup is followed by an unwind(just to covert into object) first question does it affect query performance? and if yes how to do that in optimised manner
Note: all lookup's will return only one object
For Ex:
xyz.aggregate([
{ $lookup:{ ----}} //first lookup
{$unwind :{----}} //first unwind
{ $lookup:{ ----}} //second lookup
{$unwind :{----}} //second unwind
{ $lookup:{ ----}} //third lookup
{$unwind :{----}} //third unwind
{ $lookup:{ ----}} //fourth lookup
{$unwind :{----}} //fourth unwind
])
In reference to comments, here is advanced $lookup:
$lookup: {
from: 'accounts',
let: { "localAccountField": "$account" },
pipeline: [
{
$match: {
$expr: {
$eq: ["$_id", "$$localAccountField"]
}
}
},
{
$project: {
_id: 1,
user: 1
}
},
{
$lookup: {
from: 'users',
let: { 'localUserField': "$user" },
pipeline: [
{
$match: {
$expr: {
$eq: ["$_id", "$$localUserField"]
}
}
},
{
$project: {
_id: 1,
username: "$uid",
phone:"$phoneNumber",
email: "$email.add",
name: {
$concat: [
"$profile.name.first",
' ',
"$profile.name.last"
]
},
}
}
],
as: "users"
}
},
{
$lookup: {
from: 'documents',
let: { 'localDocumentField': "$user" },
pipeline: [
{
$match: {
$expr: {
$eq: ["$user", "$$localDocumentField"]
},
status:"verified",
"properties.expirydate": { $exists: true, $ne: "" },
name: "idcard"
}
},
{
$project: {
_id: 0,
cnic: "$properties.number"
}
}
],
as: "documents"
}
}
],
as: 'account'
}

how to use $groupby and transform distinct value mongodb

How to transform the data using $if $else groupby condition MongoDB?
This playground should return two object who belongs to text with "tester 2" and "tester 3" also if I have multiple object in history collection it should also check with last object not will all object how it is possible
So condition should say if history's date is $gt then main collection should return nothing else return the matched criteria data.
db.main.aggregate([
{
$lookup: {
from: "history",
localField: "history_id",
foreignField: "history_id",
as: "History"
}
},
{
$unwind: "$History"
},
{
"$match": {
$expr: {
$cond: {
if: {
$eq: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
},
then: {
$and: [
{
$gt: [
"$date",
"$History.date"
]
},
{
$eq: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
}
]
},
else: {}
}
}
}
}
])
MongoPlayground
If I understand you correctly, it is what you are trying to do:
db.main.aggregate([
{
$lookup: {
from: "history",
let: {
main_history_id: "$history_id",
main_user_id: { $toString: "$sender_id" }
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$history_id",
"$$main_history_id"
]
},
{
$eq: [
"$user_id",
"$$main_user_id"
]
}
]
}
}
}
],
as: "History"
}
},
{
$unwind: {
path: "$History",
preserveNullAndEmptyArrays: true
}
},
{
$sort: {
_id: 1,
"History.history_id": 1,
"History.date": 1
}
},
{
$group: {
_id: "$_id",
data: { $last: "$$ROOT" },
History: { $last: "$History" }
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$data",
{ History: "$History" }
]
}
}
},
{
"$match": {
$expr: {
$or: [
{
$eq: [
{ $type: "$History.date" },
"missing"
]
},
{
$ne: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
},
{
$and: [
{
$eq: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
},
{
$gte: [
"$date",
"$History.date"
]
}
]
}
]
}
}
}
])
MongoPlayground