Check for non-existing field in lookup pipeline - mongodb

How to check if a field is not existing inside lookup expression? The answers in similar questions are not helpful (e.g. {$eq : null} or $exists:true).
For example, I want to lookup inventory only if disabled is not existing.
db.orders.aggregate([
{
$lookup: {
from: "inventory",
let: {item: "$item"},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: ["$sku", "$$item" ]
},
{
$eq: [ "$disabled", null ]
}
]
}
}
},
],
as: "inv"
}
}
])
A playground sample is here

You can use $exists outside the $expr:
db.orders.aggregate([
{
$lookup: {
from: "inventory",
let: {item: "$item"},
pipeline: [
{
$match: {
$and: [
{$expr: {$eq: ["$sku", "$$item"]}},
{disabled: {$exists: false}}
]
}
}
],
as: "inv"
}
}
])
See how it works on the playground example

you could use:
{ $match: { someField: { $exists: true } } }
before the look up, to filter out the documents that you do not want to look up

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

How to not return lookup results in mongdb

I would like to return accounts by checking if the account is used in any orders by using lookup feature. But i don't want to return lookup results. How can I ignore/remove/exclude the lookup results
Account.aggregate([
{
$match: {
type: {$eq: type}
},
},
{
$lookup:
{
from: "orders",
let: {accountId: {$toString : "$_id"}},
pipeline: [
{
$match:
{
$expr:
{
$and:
[
{$eq: ["$$accountId", "$usedAccountId"]},
{$eq: ["$orderState","COMPLETED"]
]
}
}
}
],
as: "orders"
}
}
])
With above query, I get the following results. I want to get rid of orders array
[
{
//accountObject,
orders: [
//orderObject
]
}
]

getting problem with condition in mongodb

See my condition does work fine for my history's first collection but for second it does not work either If I replace my specified id with 5e4a8d2d3952132a08ae5724 that exists in my second object of history's collection return me all data which is not correct because it's date is greater then main collection's date so it should return me nothing please suggest how to fix it.
db.main.aggregate([
{
$lookup: {
from: "history",
localField: "history_id",
foreignField: "history_id",
as: "History"
}
},
{
$unwind: "$History"
},
{
"$match": {
$expr: {
$cond: {
if: {
$eq: [
"5e4a8d2d3952132a08ae5764",
"$History.user_id"
]
},
then: {
$and: [
{
$gt: [
"$date",
"$History.date"
]
},
{
$eq: [
"5e4a8d2d3952132a08ae5764",
"$History.user_id"
]
}
]
},
else: {}
}
}
}
}
])
when I put two object into history collection it does not work either MongoPlayground
Here is working playground with single history object https://mongoplayground.net/p/hrNofrq1c3S
The reason, why your query (which is posted in the OP) is not working because, you have not specified anything in else part. So, the better approach will be with '$filter' operator.
You can try the below:
db.main.aggregate([
{
$lookup: {
from: "history",
localField: "history_id",
foreignField: "history_id",
as: "History"
}
},
{
$project: {
"History": {
$filter: {
input: "$History",
as: "his",
cond: {
$and: [
{
$lt: [
"$$his.date",
"$date"
]
},
{
$eq: [
"5e4a8d2d3952132a08ae5764",
"$$his.user_id"
]
}
]
}
}
},
data: 1,
history_id: 1,
sender_id: 1,
text: 1,
date: 1
}
},
{
$unwind: "$History"
}
])
MongoPlayGroundLink

$match expr in same document does not work

How to transform the data using $if $else condition MongoDB
mongoPlayground
I am getting worst digging into $if $expr condition
This playground should return nothing because date is $gt then main collection but it does return me data.
So condition should say if history's date is $gt then main collection should return nothing else return the matched criteria data.
the first history record only is used, as it has the same _id as the history_id in the main collection
so if you check the first history document
{
"_id": ObjectId("5e4e755b380054797d9db627"),
"user_id": "5e4e74eb380054797d9db625",
"history_id": ObjectId("5e4e755b380054797d9db627"),
"date": 1587650683433,
"__v": 1
}
and your query
db.main.aggregate([
{
$lookup: {
from: "history",
localField: "history_id",
foreignField: "_id",
as: "History"
}
},
{
$unwind: "$History"
},
{
"$match": {
$expr: {
$cond: {
if: {
$eq: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
},
then: {
$and: [
{
$gt: [
"$date",
"$History.date"
]
},
{ // also, this part has no meaning as the same condition is used in the if part
$eq: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
}
]
},
else: {}
}
}
}
}
])
the if condition is not satisfied, as the user_id in history model "5e4e74eb380054797d9db625" does not equal to the specified id "5e4e74eb380054797d9db623"
so, it goes to the else part which is getting all the documents in the main collection
note: I've added some comment in the query, could you check it too?
If I am not wrong I guess this is what you're expecting :-
db.main.aggregate([
{
$lookup: {
from: "history",
localField: "history_id",
foreignField: "_id",
as: "History"
}
},
{
$unwind: "$History"
},
{
"$match": {
$expr: {
$and: [
{
$eq: [
"$_id",
"$History.user_id"
]
},
{
$gt: [
"$date",
"$Histoy.date"
]
}
]
}
}
}
])
Well, few modification might be needed to fulfill your need.