SQL equivalent queries in MongoDB - mongodb

I'm converting my SQL queries into MongoDB. I have the following SQL statement which checks an input and perform the query accordingly.
(score_min = -1 OR Scores BETWEEN score_min AND score_max)
Scores is a field name, which I want to filter
Still couldn't figure out the best way to perform this query in a MongoDB aggregate pipeline. Any suggestions please?

You can achieve the behaviour with a $expr in a simple find. Not a must to use aggregation pipeline.
db.collection.find({
$expr: {
$or: [
{
// $eq: [<score_min>, -1]
$eq: [
<score_min>,
-1
]
},
{
$and: [
{
// $gte: ["$Scores", <score_min>]
$gte: [
"$Scores",
<score_min>
]
},
{
$lte: [
// $gte: ["$Scores", <score_max>]
"$Scores",
<score_max>
]
}
]
}
]
}
})
Here is the Mongo playground for your reference.

Related

Perform $group and count in mongoDB aggregation

Given that I have a complex grouping requirement, I was wondering what would be the best approach to achieving my desired result.
My data (result of $project stage) would look something like this:
{
_id:$id
status:"available"
inspectionStatus:"done"
state:"completed"
category:"One"
},
{
_id:$id
status:"booked"
inspectionStatus:"none"
state:"active"
category:"Two"
},
.
.
.
I have tried using $facet to create multiple buckets since the grouping I am trying to create are aggregations of $status + $state + $inspection, but the execution time is way unacceptable, taking something around 1639763842 milliseconds.
I can't use use $accumulator because of mongoDB version (although we can always upgrade to 4.4.x) but I am not sure whether using $accumulator would produce a better response time.
The $facet stage is included:
{
"available": [
{"$match":
{$and: [
{"status": "available"},
{"inspectionStatus": "done"}
]}
}
],
"matched": [
{"$match":
{$and: [
{"status": "booked"},
{"state": "booked"}
]
}
}
],
"inIntake": [
{"$match":
{$and: [
{"status": "available"},
{"inspectionStatus": {$ne: "done"}}
]
}
}
],
"active": [
{"$match":
{$and: [
{"status": "booked"},
{"state": "active"}
]
}
}
],
"unreturned":[
{"$match":
{"status": "forceCompleted"}
}
]
}
If you really want to push the logic to the DB, here's a solution -- but you still have to examine the XX field doc by doc:
db.foo.aggregate([
{$addFields: {XX: {$switch: {
branches: [
{ case: {
$and: [{$eq:["$status","available"]},{$eq:["$inspectionStatus","done"]}]
}, then:'AVAILABLE' },
{ case: {
$and: [{$eq:["$status","booked"]},{$eq:["$state","booked"]}]
}, then:'MATCHED' },
{ case: {
$and: [{$eq:["$status","available"]},{$ne:["$inspectionStatus","done"]}]
}, then:'IN_INTAKE' },
{ case: {
$and: [{$eq:["$status","booked"]},{$eq:["$state","active"]}]
}, then:'ACTIVE' },
{ case: {
$eq:["$status","forceCompleted"]
}, then:'UNRETURNED' },
],
default: null
}}
}}
,{$match: {XX: {$ne: null}}}
]);
The end-to-end timing on this is actually a bunch of millis better than simple find() because less material is transferred but of course the DB engine is working a little harder processing the pipeline.

Using $if or $ifNull condition inside a $match that will be executed in Jaspersoft Studio

{
$match: {
$expr: {
$or: [
{$ifNull : [$P{departmentuid},"warduid":{"$eq": {"$oid":$P{warduids} } } ] },
{$ifNull : [$P{warduids},"orderdepartmentuid": {"$eq": {"$oid":$P{departmentuid} } } ] }
]
}
}
},
I am trying to create a query that will be executed from Jaspersoft Studio. Now, the parameter that will be sent to the query is either of the two set parameters, so I created a $match that has a condition that it will only filter one parameter that will be received.
I am not quite sure if im doing the right query for this. Hope someone can help. Thanks!
The parameters that will be recieved from jaspersoft studio is either $P{departmentuid} or ${warduids}
The logic will just be, If the query recieved $P{departmentuid} parameter, It will apply departmentuid only in the whole query but if it received $P{warduid} it will apply warduid only.
Assuming when $P{departmentuid} or ${warduids}, they will be supplemented the value of null.
You could then do the followings:
db.collection.aggregate([
{
$match: {
$expr: {
$or: [
{
$and: [
{$eq: [null, $P{warduids}]},
{$eq: ["$orderdepartmentuid", $P{departmentuid}]}
]
},
{
$and: [
{$eq: [null, $P{departmentuid}]},
{$eq: ["$warduid", $P{warduids}]}
]
}
]
}
}
}
])
Here is the Mongo playground when $P{warduids} is null.
And here is the Mongo playground when $P{departmentuid} is null

MongoDB map filtered array inside another array with aggregate $project

I am using Azure Cosmos DB's API for MongoDB with Pymongo. My goal is to filter array inside array and return only filtered results. Aggregation query works for the first array, but returns full inside array after using map, filter operations. Please find Reproducible Example in Mongo Playground: https://mongoplayground.net/p/zS8A7zDMrmK
Current query use $project to filter and return result by selected Options but still returns every object in Discount_Price although query has additional filter to check if it has specific Sales_Week value.
Let me know in comments if my question is clear, many thanks for all possible help and suggestions.
It seemed you troubled in filtering nested array.
options:{
$filter: {
input: {
$map: {
input: "$Sales_Options",
as: 's',
in: {
City: "$$s.City",
Country: "$$s.Country",
Discount_Price: {
$filter: {
input: "$$s.Discount_Price",
as: "d",
cond: {
$in: ["$$d.Sales_Week", [2, 7]]
}
}
}
}
}
},
as: 'pair',
cond: {
$and: [{
$in: [
'$$pair.Country',
[
'UK'
]
]
},
{
$in: [
'$$pair.City',
[
'London'
]
]
}
]
}
}
}
Working Mongo plaground. If you need price1, you can use $project in next stage.
Note : If you follow the projection form upper stage use 1 or 0 which is good practice.
I'd steer you towards the $unwind operator and everything becomes a lot simpler:
db.collection.aggregate([
{$match: {"Store": "AB"}},
{$unwind: "$Sales_Options"},
{$unwind: "$Sales_Options.Discount_Price"},
{$match: {"Sales_Options.Country": {$in: [ "UK" ]},
"Sales_Options.City": {$in: [ "London" ]},
"Sales_Options.Discount_Price.Sales_Week": {$in: [ 2, 7 ]}
}
}
])
Now just $project the fields as appropriate for your output.

Conditional filtering in mongoDB

Can I use one of the $and filters conditionally, ie. when some condition is met I would like to use the filter otherwise do not use filter:
Collection.find({
$and: [
{ date },
{ room: [isConditionMet] ? room : [do not use room filter at all] },
]
}
Is it possible on mongo query level?
Isn't it the same as using $or?
Collection.find({
$and: [
{ date: ... },
{ $or: [
{isConditionNOTmet},
{room: ... }
]}
]
})

pipeline function in MongoDB, how to make the join

I am looking at a query in MongoDB.
Essentially, I want to join records, but only when the records in collection mongo2 meet certain conditions (those in the and statement).
I have 2 questions about this
Where can I put the local and foreign field setting. It says I cannot define them when using pipeline.
Its says that my GT and LT statements are wrong. They work in single find statements, but I am getting the error
Expression $gt takes exactly 2 arguments. 1 were passed in.
Any help will be massivel appreciated :)
Thanks guys
db.mongo.aggregate([
{ $lookup:
{
from: "mongo2",
pipeline: [
{ $match:
{ $expr:
{
$and:[{Age : {$gt:50}}, {Age : {$lt:100}}]
}
}
}
],
as: "filters"
}
}
])
The only way to access fields coming from mongo collection inside of pipeline is to define them as variables using let statement. For instance:
db.mongo.aggregate([
{
$lookup: {
from: "mongo2",
let: { "mongo_collection_id": "$_id" },
pipeline: [
{
$match: { $expr: { $eq: [ "$$mongo_collection_id", "$_id" ] } }
}
],
as: "filters"
}
}
])
Please note that you need double dollar sign ($$) to refer to that variable within pipeline. Single dollar references fields from mongo2 collection documents.
Answering second question: there are two $gt and $lt pairs in MongoDB (which might be confusing). Since you probably have to use $expr the only way is to use $gt (aggregation) so the syntax is a bit different:
{ $expr:
{
$and:[{ $gt: [ "$Age", 50 ] }, { $lt: [ "$Age", 100 ] }]
}
}