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 } } }
])
Related
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
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
])
I have the following query to be converted to DSL and executed on ES. I could not find a suitable aggregation and filter over results of aggregation available out-of-the-box in ES. As an alternative, I am fetching the 'group by count' for each id from ES and filtering the result as a part of my application logic, which is not efficient. Can you suggest any more suitable solution?
select distinct id from index where colA = "something" group by id having count(*) > 10;
index mapping
id : (string)
colA: (string)
Terms aggregation: to get distinct Ids.
Bucket selector: to return ids with doc count more than 10
{
"query": {
"bool": {
"filter": [
{
"term": {
"colA.keyword": "something" --> where clause
}
}
]
}
},
"aggs": {
"distinct_id": {
"terms": { --> group by
"field": "id.keyword",
"size": 10
},
"aggs": {
"ids_having_count_morethan_10": {
"bucket_selector": { --> having
"buckets_path": {
"count": "_count"
},
"script": "params.count>10"
}
}
}
}
}
}
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.)
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"}
}
}
]