This question already has answers here:
Multiple join conditions using the $lookup operator
(4 answers)
Closed 6 years ago.
If I were to write this in SQL it would be (sort of):
SELECT *
FROM request req, response res
WHERE req.suites_test=res.key # join
AND res.version='2.0.b1662.5' # extra conditions
AND req.suites_id='58762c40664df86d2069e2c9'
In MongoDB I can do:
# a join between request and response
db.response.aggregate([{$lookup: {from: "request", localField: "key", foreignField: "suites.test", as: "matching"} } ])
# find all requests that match a condition
db.request.find( { "suites.id": ObjectId("58762c40664df86d2069e2c9") } )
# find all responses that match a condition
db.response.find( { "version": "2.0.b1662.5" } )
How can I combine the three in a single MongoDB query?
There are a bunch of duplicates which are similar, but I can't find the exact matching duplicate. So, I'm adding an answer based on OP's request.
Based on your individual queries, you will just need to include the $match stage for the response ( before $lookup) and request ( after $unwind which follows $lookup ) collection in your aggregation pipeline. Something like below.
db.response.aggregate([{
$match: {
"version": "2.0.b1662.5"
}
}, {
$lookup: {
from: "request",
localField: "key",
foreignField: "suites.test",
as: "matching"
}
}, {
$unwind: "$matching"
}, {
$match: {
"matching.id": ObjectId("58762c40664df86d2069e2c9")
}
}])
Related
How can I use row/document variables in filters and sorting?
As you know in SQL we can filter on joins beside the foreign key Something like this
Select * From A LEFT JOIN B on A.key = B.foriegnKey AND B.key IN A.currentSelection
or even in mongo lookup
collection('A').aggregate([{
$lookup: {
from: "B",
localField: "key",
foreignField: "foreignKey",
let: { A_currentSelection: "$currentSelection" },
pipeline: [{
$match: {
$expr: { $in: ["$key", "$$A_currentSelection"] }
}
}],
as: "matches"
}
},
])
But you can't do the following in Prisma
prisma.A.findMany({
include: {
B: {
where: {
'$A.currentSelection': {
has: "$B.key"
}
}
}
}
})
Regardless of the query itself, the idea is that I can access the current row/document variables in the query, I also know that I can modify the structure of the database to get around these kinds of issues but the database is already structured in a specific manner that might break some parts of the code and it's also not viable to change the structure just because Prisma is not lacking in this part.
At first, I was using a raw query to get around this and know I've created more complex relationships in the schema to fix this in Prisma in this case, but if anyone knows a more elegant solution then I'd be grateful
I am using MongoDB. My task is to build Dashboard charts for the data. So, I am using Apache superset. I connected MongoDB to apache drill as it wont connect directly with superset. Then connected apache drill to Apachesueperset. My collection is nested. How can I process this nested data to get use for dashboard charts.My data looks as below
{
"_id": {
"$oid": "6229d3cfdbfc81a8777e4821"
},
"jobs": [
{
"job_ID": {
"$oid": "62289ded8079821eb24760e0"
},
"New": false,
"Expired": false
},
{
"job_ID": {
"$oid": "6228a252fb4554dd5c48202a"
},
"New": true,
"Expired": true
},
{
"job_ID": {
"$oid": "622af1c391b290d34701af9f"
},
"New": true,
"Expired": false
}
],
"email": "mani2090996#ail.com"
}
I am querying in apache drill as follows
SELECT flat.fill FROM (SELECT FLATTEN(t.jobs) AS fill FROM mongo.recruitingdb.flatten.`Vendorjobs` t) flat WHERE flat.fill.New = flase;
And i am getting parsing error
org.apache.drill.common.exceptions.UserRemoteException: PARSE ERROR: Encountered "." at line 1, column 123.
Superset doesn't really handle nested data very well. Drill does however, so you'll have to craft queries to produce columns that can be visualized.
Take a look here: https://drill.apache.org/docs/json-data-model/
and here: https://drill.apache.org/docs/querying-complex-data-introduction/.
UPDATE:
Try the query below. The FROM clause may not be exactly right, but you should get the idea from this.
Note that you can access maps in Drill in two ways:
tablename.mapname.field OR
mapname['field']
You can do this for any level of nesting.
SELECT mongoTable.jobs.job_ID.`$oid` AS job_ID,
mongoTable.jobs.`New` AS new,
mongoTable.jobs.`Expired` AS expired
FROM
(
SELECT flatten(jobs) AS jobs
FROM mongo.recruitingdb.flatten.`Vendorjobs` AS t1
WHERE t1.jobs.New = false
) AS mongoTable
I need to do a simple mongo query which resembles like this SQL
Select * from insights where category = 1 and param_count > param_mean + 1
Ideally you would use $redact as an aggregation expression for this, coupled with an initial $match to at least possibly use an index for the non-calculated expression:
db.collection.aggregate([
{ "$match": { "category": 1 } },
{ "$redact": {
"$cond": {
"if": { "$gt": [ "$param_count", { "$add": [ "$param_mean", 1 ] } ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
If your MongoDB "server" version is less than 2.6 without the $redact operator, then you can use $where which evaluates a JavaScript expression to boolean to return results:
db.collection.find({
"category": 1,
"$where": "this.param_count > this.param_mean + 1"
})
Which while shorter in syntax, it takes considerable more processing time due to the need to evaluate the JavaScript expression.
Where possible, then you should use $redact, or avoid calculations altogether and store the calculated evaluation in the document instead. That last statement is true for "all" databases really.
This question already has answers here:
How do I perform the SQL Join equivalent in MongoDB?
(19 answers)
Closed 6 years ago.
I want to write this query with mongodb
select *
from tab1 a, tab2 c
where a.a_id = 2
and c.c_id = 3
and a.a_id = c.c_fk_account_id_created_by
I tried this code but didn't get a response:
$cursor = $collection->find(array('$and' => array(array("a_id" => 2), array("c_id" => 3))));
I will assume you have two collections, named tab1 and tab2 in the form of
tab1
{
"_id" : ObjectId("58482a97a5fa273657ace535"),
"a_id" : NumberInt(2)
}
tab2
{
"_id" : ObjectId("58482acca5fa273657ace539"),
"c_id" : NumberInt(3),
"c_fk_account_id_created_by" : NumberInt(2)
}
You will need an aggregation query with two steps, first, $lookup to the second table, and second $match on the proper keys. Like this.
db.tab1.aggregate(
[
{
$lookup: {
"from" : "tab2",
"localField" : "a_id",
"foreignField" : "c_fk_account_id_created_by",
"as" : "c"
}
},
{
$match: {
"a_id": 2,
"c.c_id": 3
}
},
]
);
This will give you an output like this
{
"_id" : ObjectId("58482a97a5fa273657ace535"),
"a_id" : NumberInt(2),
"c" : [
{
"_id" : ObjectId("58482acca5fa273657ace539"),
"c_id" : NumberInt(3),
"c_fk_account_id_created_by" : NumberInt(2)
}
]
}
Good luck!
I wrote an article on just this type of query:
MongoDB Aggregation Framework for T-SQL Pros #3: The $lookup Operator
https://www.linkedin.com/pulse/mongodb-aggregation-framework-t-sql-pros-3-lookup-operator-finch
Essentially you are going to bring all documents from your second table into the results of the first table using the $lookup aggregation operator. You can then use the $match and $group operators to filter and aggregate your data.
It will go something like this:
db.tab1.aggregate([
{ $match:
{ "tab1.a_id": 2 }
},
{ $lookup:
{ from: "tab2",
localField: "a_id",
foreignField: "c_fk_account_id",
as: "tab2_results"
}
},
{ $match:
{ "tab2_results.c_id": 3 }
}
]}
The matching joined documents will be added to the base table's document as an array. It acts as a LEFT join in that null values from the remote table are ignored and your base table document is still returned, only missing remote data.
Hope this helps!
Bill
Let's assume tab1 and tab2 have 3 fields each as a_id, aa1, aa2 and c_id, c_fk_account_id_created_by, cc1
The query will be as follows
db.tab1.aggregate([{$match:{a_id:2}},{$lookup:{from:'tab2', localField:'c_fk_account_id_created_by', foreignField:'a_id', as:'ccArray'}},{$unwind:'$ccArray'},
{$project:{a_id:1,aa1:1, aa2:1, c_id:'$ccArray.c_id',c_fk_account_id_created_by:'$ccArray.c_fk_account_id_created_by',cc1:'$ccArray.cc1'}},{$match:{c_id:3}}])
Explanation of the above query:
As MongoDB doesn't allow to match from second table in the aggregation pipeline so we have to unwind the second table array and compare the value
select *
from tab1 a, tab2 c
where a.a_id = 2 ==> {$match:{a_id:2}}
and c.c_id = 3 ==> (Cannot be done at first so it can be acheived as ) ==> {$unwind:'$ccArray'},
{$project:{a_id:1,aa1:1, aa2:1, c_id:'$ccArray.c_id',c_fk_account_id_created_by:'$ccArray.c_fk_account_id_created_by',cc1:'$ccArray.cc1'}},{$match:{c_id:3}}
and a.a_id = c.c_fk_account_id_created_by ==> {$lookup:{from:'tab2', localField:'c_fk_account_id_created_by', foreignField:'a_id', as:'ccArray'}}
Dialect: postgres
Database version: #latest
Sequelize version: #latest
I'm trying to find out how to use an associate model. I've got 3 models: post, postCity and region. They have the following relation:
postCity (post_id, region_id) associate to post (post_id) and region (region_id). I am using a search function like this:
include: [
{
model: models.postCity,
include:[{model:models.region}],
attributes: [[models.sequelize.fn('count', 'post_id'), 'count']],
}
],
where: {
$or: [
{
"create_by" : {$not: 67}
},
{
// "postCities.region_name":{$iLike: "%Guangazhou2%"}
},
{
"description":{$iLike: "%India%"}
}
]
}
which leads to:
SELECT "post"."post_id", "post"."description", "post"."create_by",
"post"."create_time", "post"."update_time", "post"."country_id",
"postCities"."post_id" AS "postCities.post_id",
"postCities"."region_id" AS "postCities.region_id",
"postCities"."order_no" AS "postCities.order_no",
"postCities.region"."region_id" AS "postCities.region.region_id",
"postCities.region"."region_name" AS "postCities.region.region_name",
"postCities.region"."country_id" AS "postCities.region.country_id",
"postCities.region"."province_id" AS "postCities.region.province_id"
FROM "t_post" AS "post"
LEFT OUTER JOIN "t_post_city" AS "postCities"
ON "post"."post_id" = "postCities"."post_id"
LEFT OUTER JOIN "t_region" AS "postCities.region"
ON "postCities"."region_id" = "postCities.region"."region_id"
WHERE ("post"."create_by" != 67 OR "post"."description" ILIKE '%India%');
When I uncomment "postCities.region_name":{$iLike: "%Guangazhou2%"} then I get this error
column post.postCities.region_name does not exist
I simply like to my query to be like this
... WHERE ("post"."create_by" != 67
OR "post"."description" ILIKE '%India%'
OR "postCities.region_name" ILIKE: "%Guangazhou2%")
Update
I also tried to include [{model:models.region, where:{"region_name":{$iLike: "%Guangazhou2%"}}}] but this doesn't give me the appropriate result.
In order to add condition to included tables, you should wrap condition with $ symbol, like it:
include: [{
model: models.postCity,
include:[{model:models.region}],
attributes: [[models.sequelize.fn('count', 'post_id'), 'count']],
}],
where: {
$or: [{
"create_by" : {$not: 67}
}, {
"$postCities.region.region_name$":{$iLike: "%Guangazhou2%"}
}, {
"description":{$iLike: "%India%"}
}]
}