How to convert sql query with exist into mongodb query - sql

I have two documents on mongodb, these are percentages and items. I'm good at SQL, I can write PLSql query as follows but i can not convert to mongodb query. Because my mongodb level of knowledge is at the beginning. Actually I know I have to use $gt for the and condition. But I don't know how I can say not exists or union keyword for mongodb. How can I write mongodb query? which keywords should i search for?
select p.*, "to_top" as list
from percentages p
where p.percentage > 5
and p.updatetime > sysdate - 1/24
and not exists (select 1
from items i
where i.id = p.p_id
and i.seller = p.seller)
order by p.percentage desc
union
select p2.*, "to_bottom" as list
from percentages p2
where p2.percentage > 5
and p2.updatetime > sysdate - 1/24
and exists (select 1
from items i2
where i2.id = p2.p_id
and i2.seller = p2.seller)
order by p2.percentage desc

There is no UNION for MongoDB. Luckely, each query is performed on the same collection and have very close condition, so we can implement "Mongo way" query.
Explanation
Normally, alsmost all complex SQL queries are done with the MongoDB aggregation framework.
We filter document by percentage / updatetime. Explanation why we need to use $expr
SQL JOIN / Subquery is done with the $lookup operator.
SQL SYSDATE in MongoDB way can be NOW or CLUSTER_TIME variable.
db.percentages.aggregate([
{
$match: {
percentage: { $gt: 5 },
$expr: {
$gt: [
"$updatetime",
{
$subtract: [
ISODate("2020-06-14T13:00:00Z"), //Change to $$NOW or $$CLUSTER_TIME
3600000
]
}
]
}
}
},
{
$lookup: {
from: "items",
let: {
p_id: "$p_id",
seller: "$seller"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [ "$$p_id", "$id"]
},
{
$eq: [ "$$seller", "$seller"]
}
]
}
}
},
{
$limit: 1
}
],
as: "items"
}
},
{
$addFields: {
list: {
$cond: [
{
$eq: [{$size: "$items"}, 0]
},
"$to_top",
"$to_bottom"
]
},
items: "$$REMOVE"
}
},
{
$sort: { percentage: -1 }
}
])
MongoPlayground
Note: The MongoDB aggregation has the $facet operator that allows to perform different queries on the same collection.
SCHEMA:
db.percentages.aggregate([
{$facet:{
q1:[...],
q2:[...],
}},
//We apply "UNION" the result documents for each pipeline into single array
{$project:{
data:{$concatArrays:["$q1","$q2"]}
}},
//Flatten array into single object
{$unwind:"$data"}
//Replace top-level document
{$replaceWith:"$data"}
])
MongoPlayground

why you don't import your mangoDB data into oracle and use sql(that is more easy and powerful than mango.)

Related

Seqeulize query a table with multiple where values for same column?

I have a sequelize query that looks like
const deliveriesToCancel = await Model.ShipperContract.findByPk(organizationId, {
include: [
{
model: Model.Order,
as: organizationId,
include: [
{
model: Model.Delivery,
as: "deliveries",
where: {
state: {
[Op.not]: "DELIVERED" || "CANCELED_BYL" || "CANCELED_BY_SHIPPER"
}
}
},
],
},
],
});
Is it possible to query on Delivery table with 3 possible choices for state column? or in this case, WHERE !== those 3 values?
How can I write taht in seqeulize?
If you want to select the deliveries where "state" isn't any of "DELIVERED", "CANCELED_BYL", or "CANCELED_BY_SHIPPER", you can use:
where: {
state: {
[Op.notIn]: ["DELIVERED", "CANCELED_BYL", "CANCELED_BY_SHIPPER"]
}
}
Note:
WHERE NOT IN can be slow. If your dataset is huge and your query is slow, consider looking into modifying it to an exists. Docs, Docs

Need to convert this SQL query to MongoDB

I am new to MongoDB. I need to convert this SQL code to MongoDB
select TOP 5 r.regionName, COUNT(c.RegionID)
from region as r,
company as c
where c.RegionID = r._id
group by r.regionName
order by COUNT(c.RegionID) DESC;
Option 1. You can use the aggregation framework with $lookup, $group, $project , $sort and $limit stages, but this seems like a wrong approach since the true power to change relation database with mongoDB is the denormalization and avoidance of join ($lookup) like queries.
Option 2. You convert your multi-table relational database schema to document model and proceed with simple $group, $project, $sort and $limit stage aggregation query for the above task.
Since you have not provided any mongodb document examples it is hard to provide how your queries will look like ...
Despite of my comment I try to give a translation (not tested):
db.region.aggregate([
{
$lookup: // left outer join collections
{
from: "company",
localField: "_id",
foreignField: "RegionID",
as: "c"
}
},
{ $match: { c: { $ne: [] } } }, // remove non-matching documents (i.e. INNER JOIN)
{ $group: { _id: "$regionName", regions: { $addToSet: { "$c.RegionID" } } } }, // group and get distinct regions
{ $project: { regionName: "$_id", count: { $size: "$regions" } , _id: 0} } // some cosmetic and count
{ $sort: { regionName: 1 } }, // order result
{ $limit: 5 } // limit number or returned documents
])

SQLite script to MongoDB

I'm a newbie on MongoDB. And I need help. I have a small project with SQLite (7 tables and 1 view). And I need to make this project on MongoDB, I'm using Studio 3T, I'm already migrate SQLite tables to MongoDB collections, but now I need to make (VIEW/TEST) for test this project. Please help how to write this SQL script with MongoDB.
SQLITE:
MongoDB:
SQLIte script I want to make with MongoDB:
CREATE VIEW rezultatas AS
SELECT p.pavadinimas AS detales_pavadinimas,
SUM(d.pagamintas_kiekis) AS pagamintas_kiekis,
SUM(z.gamybos_islaidos) AS vidutine_kaina,
STRFTIME('%m', d.pagaminimo_data) AS menuo,
STRFTIME('%Y', d.pagaminimo_data) AS metai
FROM detales d,
zinynas z,
produktas p
WHERE (z.detale_id = p._id_) AND
(d.detale_id = z.detale_id) AND
(d.pagaminimo_data >= z.data_nuo) AND
NOT EXISTS (
SELECT *
FROM zinynas
WHERE (d.detale_id = detale_id) AND
(d.pagaminimo_data >= data_nuo) AND
(z.data_nuo < data_nuo)
)
GROUP BY p.pavadinimas,
STRFTIME('%m', d.pagaminimo_data),
STRFTIME('%Y', d.pagaminimo_data)
I had to guess some things due to the lack of schemes but the basic layout should work.
We're going to use $createView with these parameters as input:
db.createView('rezultatas', 'produktas', pipeline)
Meaning our pipeline creating the view starts with the produktas collection.
The pipeline to use:
[
{ // match the documents from the zinyas collection.
$lookup:
{
from: "zinynas",
let: { produktas_id: "$_id" }, // i'm guessing its _id
pipeline: [
{ $match:
{ $expr: { $eq: [ "$detale_id", "$$produktas_id" ] }}
},
],
as: "z"
}
},
{
$unwind: "$z"
},
{ // match the documents from the detales collection. only keep the one with maximum data_nuo value.
$lookup:
{
from: "detales",
let: { z_detale_id: "$z.detale_id", z_data_nuo: "$z.data_nuo" },
pipeline: [
{ $match:
{
$and: [
{ $expr: { $eq: [ "$detale_id", "$$z_detale_id" ] }},
{ $expr: { $gte: [ "$pagaminimo_data", "$$z_data_nuo"]}}
]
}
},
{
$sort: {
data_nuo: -1
}
},
{
$limit: 1
}
],
as: "d"
}
},
{
$unwind: "$d"
},
{ // end up saving the fields we want.
$group: {
_id: { pavadinimas : "$pavadinimas", month: {$month: "$d.pagaminimo_data"}, year: {$year: "$d.pagaminimo_data"}},
pagamintas_kiekis: {$sum: "$d.pagamintas_kiekis"},
vidutine_kaina: {$sum: "$z.gamybos_islaidos"},
month: {$first: {$month: "$d.pagaminimo_data"}},
year: {$first: {$year: "$d.pagaminimo_data"}},
detales_pavadinimas: {$first: "$pavadinimas"}
}
}
]

How to Make a Lookup connection between two Collection

Goal:
This sql and its result should be the same result from mongoDB's query code.
In order words, same result but for mongoDB.
Problem:
How to you make a lookup connection in relation to People and Role in Mongo DB's query code?
Info:
I'm new in mongo DB
SQL code
SELECT
a.*,
'.' AS '.',
b.*,
'.' AS '.',
c.*
FROM
[db1].[dbo].[People_Course_Grade] a
INNER JOIN [db1].[dbo].[People] b on a.PeopleId = b.PeopleId
INNER JOIN [db1].[dbo].[Role] c on b.RoleId = c.RoleId
Json data:
Role:
[{"RoleId":1,"Name":"Student"},{"RoleId":2,"Name":"Teacher"}]
People_Course_Grade:
[{"People_Course_GradeId":1,"PeopleId":1,"CourseId":1},
{"People_Course_GradeId":2,"PeopleId":2,"CourseId":1},
{"People_Course_GradeId":3,"PeopleId":3,"CourseId":2},
{"People_Course_GradeId":4,"PeopleId":1,"CourseId":2}]
Course:
[{"CourseId":1,"Name":"Java"},{"CourseId":2,"Name":"Java II"},
{"CourseId":3,"Name":"Statistik 1"}]
db.People_Course_Grade.aggregate([
{
$lookup:{
from: "People",
localField: "people_id",
foreignField: "_id",
as: "people"
}
},
{ $unwind:"$people" },
{
$project:{
course_id : 1,
people_id : 1,
// grade_id : 1,
Name : "$people.Name",
}
}
]);
You need to start with double $lookup since you have three collections. Then you can use $arrayElemAt to always get single element from lookup's result. To flatten your structure you can use $replaceRoot with $mergeObjects (promotes all the fields from people and course to root level.
db.People_Course_Grade.aggregate([
{
$lookup:{
from: "Role",
localField: "PeopleId",
foreignField: "RoleId",
as: "people"
}
},
{
$lookup:{
from: "Course",
localField: "CourseId",
foreignField: "CourseId",
as: "course"
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$$ROOT",
{ $arrayElemAt: [ "$people", 0 ] },
{ $arrayElemAt: [ "$course", 0 ] },
]
}
}
},
{
$project: {
people: 0,
course: 0
}
}
])
Mongo Playground
$arrayElemAt can always be replaced with $unwind like you tried. You also have a naming conflict on name field so probably you need to run $project to rename one of those fields - otherwise you'll get only one of them in final result.

How to implement the follow RMDB query in MongoDB

My team started to use MongoDB now and wanna migrate some sql to Mongo.
For example, I have an order table and has the fields price and quanty.I want to query the price*quanty greater than 100. sql is like below
select * from Order where price * quanty > 100;
How to use "price * quanty" this kind query in Mongo?
Thanks.
You can do this by using the $expr operator to use aggregation expressions within your query:
db.orders.find({
$expr: {
$gt: [
{ $multiply: ["$price", "$quantity"] },
100
]
}
})
As JohnnyHK points out you can use $expr, but as an alternative you can also use aggregation to first create a new field that is the product of two other fields:
db.orders.aggregate([
{ $set: { product: { $multiply: [ "$price", "$quantity" ] } } }
])
Note: $set is new in 4.2 and just an alias for $addFields
Then add a $match stage that only matches documents with the new product field meeting your condition:
db.orders.aggregate([
{ $set: { product: { $multiply: [ "$price", "$quantity" ] } } },
{ $match: { product: { $gt: 100 } } }
])