How to merge multiple dynamic queries - javascript

I'm using node to communicate with my postgresql database.
I have a list of cars:
[{id:1, areaId: 1},
{id:2, areaId: 2},
{id:3, areaId: 2}]
areaId is a column in another table (say areas), and I want to fetch the area name for each car:
select name from areas
where id = areaId
How can I build a list containing all the cars with the area name attached?
The naive approach is to query the database for each object:
const query = `select name from areas
where id = $1`;
return pg.query(query, car.areaId);
But it seems like a lot of queries to be executed.

You should be able to select multiples Id's at the same time as this.
SELECT name
FROM areas
where ID in (5263, 5625, 5628, 5621)

Yes, you can specify multiple car.ids and fetch car.name and area.name and return them together.
Further you can sort the response by car.id using ORDER BY. I am not aware of any way to enforce the ordering based on the order of the passed in IDS, but you could easily sort the results in memory very quickly with JavaScript.
There are multiple ways to do this in SQL: inner join, full join, subselect...maybe more. I'll demonstrate the "inner join" as it's usually the most efficient, and some SQL query planners will convert subselects to inner joins anyway.
You haven't specified, but assuming you're using node-postgres...here's an answer when carIds is already defined, as an array:
Inner join
const query = `SELECT car.id, car.name, areas.name FROM car INNER JOIN area ON car.areaId WHERE car.id = ANY (${carIds}) ORDER BY car.id`
Finally:
return pq.query(query, carIds)

Related

Break map() function in React JS based on condition

Requirement: Basically I have an array of employee object in React JS, say empList. This empList contains primitive fields & again an inner array of another "address" objects, say addressList. I want to fetch data for all employees if they belong to city "ABC". They can have multiple address in city "ABC", but they should be fetched only once & pushed into finalList only once.
Problem : I am able to filter the employees having address in city "ABC" but in case, they have multiple address in city "ABC", then they are added to the finalList multiple times. So, I want to check for all addresses for an employee & in case, any one is found in city "ABC", I want to add it to finalList, break this inner map() function & go to outer map() to check for next employee.
Below is my code snippet.
var finalList =[];
empList.map(function(employee) {
var valid = employee.addressList.map(function(address) {
if (address.city.startsWith("ABC")) {
finalList.push(employee);
//Employee pushed to validList once, so now break from inner map() function & goto second line/execute on next employee object
}
}); //.slice(0,1); Slice doesn't work here since I want the condition to be true first, then break it.
You can use the some which tests whether at least one element in the array passes the test condition.
Read about some here.
var finalList = empList.filter(e => e.addressList.some(a => a.city.startsWith("ABC")));
Also I've updated your logic to use filter (instead of map) which creates a new array with all elements that pass the provided condition.
You can read about filter at here.

Sequelize how to return result as a 2D array instead of array of objects?

I am using Sequelize query() method as follows:
const sequelize = new Sequelize(...);
...
// IMPORTANT: No changed allowed on this query
const queryFromUser = "SELECT table1.colname, table2.colname FROM table1 JOIN table2 ON/*...*/";
const result = await sequelize.query(queryFromUser);
Because I am selecting two columns with identical names (colname), in the result, I am getting something like:
[{ "colname": "val1" }, { "colname": "val2" }...], and this array contains values only from the column table2.colname, as it is overwriting the table1.colname values.
I know that there is an option to use aliases in the SQL query with AS, but I don't have control over this query.
I think it would solve the issue, if there was a way to return the result as a 2D array, instead of the array of objects? Are there any ways to configure the Sequelize query that way?
Im afraid this will not be possible without changes in the library directly connecting to the database and parsing its response.
The reason is:
database returns BOTH values
then in javascript, there is mapping of received rows values to objects
This mapping would looks something like that
// RETURNED VALUE FROM DB: row1 -> fieldName:value&fieldName:value2
// and then javascript code for parsing values from database would look similar to that:
const row = {};
row.fieldName = value;
row.fieldName = value2;
return row;
As you see - unless you change the inner mechanism in the libraries, its impossible to change this (javascript object) behaviour.
UNLESS You are using mysql... If you are using mysql, you might use this https://github.com/mysqljs/mysql#joins-with-overlapping-column-names but there is one catch... Sequelize is not supporting this option, and because of that, you would be forced to maintain usage of both libraries at ones (and both connected)
Behind this line, is older answer (before ,,no change in query'' was added)
Because you use direct sql query (not build by sequelize, but written by hand) you need to alias the columns properly.
So as you saw, one the the colname would be overwritten by the other.
SELECT table1.colname, table2.colname FROM table1 JOIN table2 ON/*...*/
But if you alias then, then that collision will not occur
SELECT table1.colname as colName1, table2.colname as colName2 FROM table1 JOIN table2 ON/*...*/
and you will end up with rows like: {colName1: ..., colName2: ...}
If you use sequelize build in query builder with models - sequelize would alias everything and then return everything with names you wanted.
PS: Here is a link for some basics about aliasing in sql, as you may aliast more than just a column names https://www.w3schools.com/sql/sql_alias.asp
In my case I was using:
const newVal = await sequelize.query(query, {
replacements: [null],
type: QueryTypes.SELECT,
})
I removed type: QueryTypes.SELECT, and it worked fine for me.

Autocomplete values using array

Is it possible to use two arrays to insert data into values rather then hard coding the names of the users in tabulator.
One array would hold the username while the other would hold the actual name of the user.
{title:"Approver", field:"Approver", editor:"autocomplete", editorParams:
{
values:{
"jd1":"John Doe",
"mm12":"Marty McFly",
}
}
}
You should use Object.keys(values) and Object.values(values) to obtain username and fullname as two arrays, respectively.

Sequelize count associations in findAll

Let's say you have a queues table, agent_queues, and agents table. An agent can be in many queues, a queue can have many agents. Now let's say you're trying to get a list of queues and the number of agents in those queues. I would expect something like the following to work:
queues.findAll({
include: ['agentQueues'],
group: ['queues.name', 'queues.matcher', 'queues.id'],
attributes: [[Sequelize.fn('count', Sequelize.col('agentQueues.id')), 'agentCount']]
})
Instead it produces something like:
SELECT "queues".*
FROM (SELECT
"queues"."name",
"queues"."matcher",
"queues"."id",
count("agentQueues"."queueId") AS "agentCount"
FROM "queues" AS "queues"
GROUP BY "name", "matcher", "id"
) AS "queues" LEFT OUTER JOIN "agent_queues" AS "agentQueues" ON "queues"."id" = "agentQueues"."queueId";
Where both the group by and count are in the subquery as opposed to the main query. What am I doing wrong here?
An ideal query would look something like this:
SELECT name, matcher, count(agent_queues."queueId") as agentCount FROM queues
LEFT OUTER JOIN agent_queues ON "agent_queues"."queueId" = queues.id
GROUP BY name, matcher;
The result I'm looking for is something like this:
[{ name: 'Some Queue', matcher: '1 = 1', agentCount: 2 }]
It is a bit old question but this problem is also with new versions of sequelize. My best workaround was using a literal instead of fn and count functions.
This code should generate a sql statement you expect.
queues.findAll({
group: ['queues.name', 'queues.matcher'],
attributes: ['name', 'matcher',[literal(`(SELECT count(*) FROM "agentQueues"
WHERE queue."id" = "agentQueues"."queueId"])`, 'agentCount')]]
})

cross-referencing two firebase arrays to obtain data

I was wondering if there's an easy way to pull out a value from one array based on its corresponding name.
Here, I've obtained the user email from the "coupons" collection. Now I would like to search through the "users" collection, find similar email, and output its corresponding "Name" ("Wes Haque Enterprises") to a $scope variable.
I already have references to both collections and $scope objects which have those references stored.
I just wanted to know if there's an easy way to traverse through the $scope.users object looking for the string "wes#wes.com" and then extracting "Wes Haque Enterprises" from it. Thanks.
Assuming that you don't really want to iterate (traverse?) over a bunch of arrays but instead query for the data you need...
You can query the users node for the data you need. In MacOS:
FQuery *allUsers = [usersRef queryOrderedByChild:#"emailAddress"];
FQuery *thisUser = [allUsers queryEqualToValue:#"wes#wes.com"];
[thisUser observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
for ( FDataSnapshot *child in snapshot.children) {
NSLog(#"%#", child);
}
}]
The result of the query will contain "Wes Haque Enterprises"
Or
ref.orderByChild("emailAddress").equalTo("wes#wes.com").on("child_added", function(snapshot) {
console.log(snapshot.key());
});

Categories

Resources