Couchbase - join using field without any relationship - couchbase

I have two documents:
Document Id: A
{
"name":"abc",
"phone":"123"
}
and
Document Id: B
{
"name":"abc",
"state":"test-state"
}
Is it possible to join two documents using N1QL based on name field ? If yes, how can i achieve it?
I have found a similar question here, but is there a way to join documents without any relation between them?

Currently Couchbase Joins are through document key relation.
Check this out https://dzone.com/articles/visually-explaining-n1ql-joins3
You can achieve this but not best approach
SELECT a, b FROM default a
UNNEST (SELECT * FROM default WHERE b.state = "xyz") AS b
WHERE a.name = b.name AND a.phone = "123"

Related

MySQL Select from table return all, plus one column with condition and another query

I'm pretty basic at MySQL queries. I work on a Laravel web app, at this point it comes to edit the User Role's part. I have a table that lists options for a user's role (called mst_level), and another table reflects the list of users who has that role (called mst_user_level). Been search this topic several times, but always found a different case.
mst_level
mst_user_level
Expected Output:
Select all levels for a spesific user_id, and return all columns
in mst_level + 1 column called "checked", with the
condition if the user has that role in mst_user_level, return true,
else return false.
This is what I already did, which I know it's wrong
select a.*, coalesce(true, false) as checked from my_db_name.mst_level a
inner join my_db_name.mst_user_status b on a.id = b.mst_level_id
where b.mst_user_id = '363fdeea-5330-490a-b4db-34e32a3526d6'
Anyone can help me out with this? So much Appreciated...
You can do it with EXISTS:
SELECT m.*,
EXISTS (
SELECT 1
FROM my_db_name.mst_user_status s
WHERE s.mst_level_id = m.id
AND s.mst_user_id = '363fdeea-5330-490a-b4db-34e32a3526d6'
) AS checked
FROM my_db_name.mst_level m;
Or with a LEFT JOIN where the conditions are set in the ON clause:
SELECT m.*, s.mst_level_id IS NOT NULL AS checked
FROM my_db_name.mst_level m LEFT JOIN my_db_name.mst_user_status s
ON s.mst_level_id = m.id AND s.mst_user_id = '363fdeea-5330-490a-b4db-34e32a3526d6';

MySQL Select where Tag = "First tag" AND Tag = "Another tag" using reference table

I have the following database structure:
The table peekable_tag is essentially a dictionary of lots of different tags.
The table peekable_url is a table full of different URLs and then each URL can be referenced to multiple tags.
For example, a url such as carmechanic.com can have both the tags "Car" and "Mechanic" assigned to it.
And a url such as teslacardirectory.com could have three tags, "Car", "Tesla" and "Mechanic" assigned to it.
using the following query i can pull all of the urls up that have 1 keyword assigned, for example, the keyword "Car"
Select
peekable_tag.tag,
peekable_url.id,
peekable_url.url
From
peekable_tag Inner Join
peekable_urltotag On peekable_urltotag.peekable_tag_id = peekable_tag.id Inner Join
peekable_url On peekable_urltotag.peekable_URL_id = peekable_url.id
Where
peekable_tag.tag = 'Car'
Would return both URLs.
However...
How do I alter this so i can narrow the search down with multiple keywords?
So if i searched for "Car" and "Tesla" as a keyword, only teslacardirectory.com would appear.
I tried
peekable_tag.tag = 'Car' AND peekable_tag.tag = 'Tesla'
But that doesn't return any results.
I thought about nesting one search query inside another, but then I would be limited to only using two keywords. Or nest three queries, but then id be limited to 3 keywords... Is there a way of achieving what im trying to do without limiting how many keywords can be used?
Use aggregation:
Select u.id, u.url
From peekable_tag t Inner Join
peekable_urltotag ut
On ut.peekable_tag_id = t.id Inner Join
peekable_url u
On ut.peekable_URL_id = u.id
Where t.tag in ('Car', 'Tesla')
group by u.id, u.url
having count(*) = 2; -- both tags match

NodeJS + MySQL, UPDATE with a JOIN, ambiguous column name

First of all, I understand why I'm getting this error message, and I know of a way to solve it, but I'm hoping for something more efficient than what I have in mind. Here is basically what I have:
UPDATE customer c
JOIN customer d ON c.customer_id = d.parent_customer_id
SET ?
WHERE d.customer_type = "Big Cheese";
So, the data being fed in to the "?" parameter looks like this:
{"customer_id": 10, "customer_name": "Cheese-It", ... }
The problem is, since I'm joining on a table that is basically itself, all of the columns have the same name. The only way I know how to fix this is edit the JSON and prefix all of the fields with the alias it needs:
{"c.customer_id": 10, "c.customer_name": "Cheese-It", ... }
I was hoping for a more elegant way of going about this. Is there a way to refactor my SQL so that it knows which table alias I want to update? Any ideas?
A subquery will do what you are wanting, but it's actually less efficient, as subqueries inside the WHERE clause are generally performance killers. I feel like you have to be parsing the JSON into SQL, so I would simply add the alias at that point.
Anyway, for reference, here's how you can refactor the SQL to not need an alias:
UPDATE customer
SET ?
WHERE customer_id IN (
SELECT c.customer_id
FROM customer c
JOIN customer d ON c.customer_id = d.parent_customer_id
WHERE d.customer_type = 'Big Cheese'
);
NOTE: this is untested
EDIT:
On second thought, an EXISTS clause would be slightly better for performance:
UPDATE customer c
SET ?
WHERE EXISTS (
SELECT 1
FROM customer d
WHERE d.parent_customer_id = c.customer_id
AND d.customer_type = 'Big Cheese'
);
Either way should work. As long as you don't have a JOIN in the update, there is only one table the SET columns can reference, so you will avoid the ambiguous column name error.
I know this is an older question, but I found a better solution that doesn't have the performance hit. You can add the alias to your property names in the object you're updating.
Here is the helper function to translate the standard property names with an alias.
const allowUpdate = ['name']
function addUpdateAlias(updated, alias) {
let validUpdate = {}
for (let p in updated) {
if (allowUpdate.indexOf(p) > -1) {
validUpdate[`${alias}.${p}`] = updated[p]
}
}
return validUpdate;
}
Now wrap the object you want to update with the function above and the alias is applied in the update!
Your parameters would then be: [addUpdateAlias(customer, 'c')] to pass into your original query.

Return a different datatype from postgresql

I have the below query in PG
SELECT
project.project_id,
project.project_name,
category.category_name,
array_agg(row(skill.skill_name,projects_skills.projects_skills_id)) AS skills
FROM project
JOIN projects_skills ON project.project_id = projects_skills.project_id
JOIN skill ON projects_skills.skill_id = skill.skill_id
JOIN category ON project.category_id = category.category_id
GROUP BY project.project_name,project.project_id, category.category_name;
of particular interest is the below line which seems to return a pseudo-type tuple
array_agg(row(skill.skill_name,projects_skills.projects_skills_id)) AS skills
I'm unable to create a view of this because of the pseudo type - in addition to this, the row function seems to return a tuple set like the below:
skills: '{"(Python,3)","(Node,4)","(Javascript,5)"}' }
I could painfully parse it in JavaScript by replacing '(' to '[' etc. but could I do something in postgres to return it preferably as an object?
One possible solution is to register a row type (once):
CREATE TYPE my_type AS (skill_name text, projects_skills_id int);
I am guessing text and int as data types. Use the actual data types of the underlying tables.
SELECT p.project_id, p.project_name, c.category_name
, array_agg((s.skill_name, ps.projects_skills_id)::my_type) AS skills
FROM project p
JOIN projects_skills ps ON p.project_id = ps.project_id
JOIN skill s ON ps.skill_id = s.skill_id
JOIN category c ON p.category_id = c.category_id
GROUP BY p.project_id, p.project_name, c.category_name;
There are many other options, depending on your version of Postgres and what you need exactly.
As well as the excellent suggestions to use JSON in the comments, and #Erwin 's to use a registered composite type, you can use a two-dimension array, or a multivalues approach:
Just replace your line
array_agg(row(skill.skill_name::text,projects_skills.projects_skills_id::text)) AS skills
with the following:
Two dimension array option 1
array_agg(array[skill.skill_name::text,projects_skills.projects_skills_id::text]) AS skills
-- skills will be '{{Python,3},{Node,4},{Javascript,5}}', thus
-- skills[1][1] = 'Python' and skills[1][2] = '3' -- id is text
Two dimension array option 2
array[array_agg(skill.skill_name),array_agg(projects_skills.projects_skills_id)] AS skills
-- skills will be '{{Python,Node,Javascript},{3,4,5}}', thus
-- skills[1][1] = 'Python' and skills[2][1] = '3' -- id is text
Multivalues
array_agg(skill.skill_name) AS skill_names,
array_agg(projects_skills.projects_skills_id) AS skills_ids
-- skills_names = '{Python,Node,Javascript}' and skill_ids = '{3,4,5}', thus
-- skills_names[1] = 'Python' and skills_ids[1] = 3 -- id is integer

MySQL self-join for an EAV based stock control application [duplicate]

This question already has answers here:
Zend Select with self join overwriting fields
(3 answers)
Closed 2 years ago.
This question relates to the schema I suggested in my original question regarding a stock control application.
I'm trying to create a MySQL query that provides the current stock for a particular item.
The query is working but I wondered whether there is a more efficient way of obtaining the information I require.
SELECT 's'.*,
'v1'.'attribute_id' AS 'att1',
'v1'.'value' AS 'val1'
'v2'.'attribute_id' AS 'att2',
'v2'.'value' AS 'val2'
FROM 'eav_ev' AS 'ev1'
INNER JOIN 'stock' AS 's' ON s.id = ev1.stock_id
INNER JOIN 'eav_ev' AS 'ev2' ON ev1.stock_id = ev2.stock_id
INNER JOIN 'eav_value' AS 'v1' ON v1.id = ev1.value_id
INNER JOIN 'eav_value' AS 'v2' ON v2.id = ev2.value_id
WHERE (ev1.entity_id = '45')
AND (ev1.value_id <> ev2.value_id)
AND (s.total > 0)
GROUP BY 'ev1'.'stock_id'
ORDER BY 'ev1'.'value_id' ASC
This returns something along the lines of
array (1) {
[0] => array(5) {
["stock_id"] => "2"
["att1"] => "3"
["val1"] => "M12"
["att2"] => "4"
["val2"] => "45"
}
}
It seems very messy but my poor brain is incapable of coming up with something better.
Any suggestions?
Instead of using attribute_id AS att1 you could also use value AS attribute_X if you store a list of attributes first. You can simply cache the query after which you can just select all needed data in 1 clear query.
Assuming you've fetched a list of attribute IDs first (i.e. SELECT attribute_id FROM eav_value), select this:
SELECT
v1.value_id AS attribute_1 -- (or whatever the ID was fetched in the first query)
v2.value_id AS attribute_2 -- (or whatever the second ID was fetched in the first query)
...