Knex.js for query as one query - javascript

Can this be done as one query so there is not multiple request to the DB with the loop? Im trying to get each cameras last photo if any.
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
let cameras = await knex({ cameras: "device_manager_camera" })
.select()
.where("owner_id", 13);
const start = async () => {
let report = [];
asyncForEach(cameras, async camera => {
let photo = await knex({ photos: "device_manager_photo" })
.where("camera_id", camera.id)
.first();
if (photo) {
report[camera.name] = photo.timestamp;
} else {
report[camera.name] = "never";
}
});
console.log(report);
};
start();

First of all, I'd recommend you to write your SQL query in plain SQL and it would be much easier to translate it to knex commands.
As for your request, I've come up with this query which returns the array of [{ camera_id, timestamp }]. It selects cameras of the owner with id 13 and joins this to max timestamps grouped query from table photos.
select
c.name,
coalesce(t.timestamp::text, 'never') as timestamp
from
cameras as c
left join (
select
p.camera_id,
max(p.timestamp) as timestamp
from
photos as p
group by
camera_id
) as t on t.camera_id = c.id
where
c.owner_id = 13;
Correct your table names and columns if necessary.
Bonus style points. I'd not recommend using timestamp as a column name. It is a reserved column in some databases and it might need quotes around it to explicitly specify it as a column in your query, which might be annoying.

Related

How to organize conditionally created gremlin query (JavaScript)

I am a beginner in gremlin with TinkerPop and have this query in JavaScript. It works fine. Since this question is not related to the query but rather how to structure it, so I don't think a graph is be needed for this.
This query solves two questions:
What restaurant near me with a specific cuisine is the highest rated?
-- set cuisines, queryOrder, limit=1 and restaurantFilter
Which restaurants are the ten highest-rated restaurants near me?
-- set limit=10 and queryOrder
// usuals
let dc = new DriverRemoteConnection(`ws://localhost:8182/gremlin`, {});
const graph = new Graph();
const __ = gremlin.process.statics;
const p = gremlin.process.P;
const order = gremlin.process.order;
const g = graph.traversal().withRemote(dc);
// limit for objects returned.
const limit: number | undefined = undefined;
// order on reviews
const queryOrder = order.desc;
// restaurant filters
const restaurantFilter = {location: "x"}
//26, 32
const cuisines = [26];
function convertObjectToGremlinPropertyFilter(
data: Record<string, any>,
g: gremlin.process.GraphTraversal
) {
return Object.keys(data).forEach((key) => {
g.has(key, data[key]);
});
}
async function init() {
const result = g.V().hasLabel("restaurant");
convertObjectToGremlinPropertyFilter(restaurantFilter, result);
const reviewQuery = __.inE("review").has("value", p.gte(2));
if (order) {
reviewQuery.order().by("value", order.desc);
}
reviewQuery.valueMap().fold();
if (cuisines.length) {
console.log("Filtering cuisines");
result.where(
__.outE("serves")
.inV()
.hasLabel("cuisine")
.hasId(p.within(...cuisines))
);
}
result
.project("restaurants", "reviews")
.by(
__.project("info", "cuisines")
.by(__.valueMap(true))
.by(
__.outE("serves").unfold().inV().hasLabel("cuisine").valueMap().fold()
)
)
.by(reviewQuery);
if (limit) {
result.limit(limit);
}
const dataRaw = await result.toList();
await dc.close();
const data = JSON.stringify(normalizeData(dataRaw as any), null, 2);
fs.writeFileSync("./data.json", data);
}
For now, I've hardcoded the limit, queryOrder, and cuisines array. And creating the query on the condition applied to them.
As you can see, this query is kind of hard to maintain and interpret what it is doing. I've done the research and didn't find any resources related to structuring conditional queries. How can I structure these kinds of queries?
Original Query:
g.V()
.hasLabel("restaurant")
.has("location", "karachi")
// Check for cuisines
.where(
__.outE("serves")
.inV()
.hasLabel("cuisine")
.hasId(p.within(id1,id2))
)
// build the object
.project("info", "cuisines", "reviews")
.by(__.elementMap())
.by(__.outE("serves").inV().hasLabel("cuisine").elementMap().fold())
// Get reviews which are greater than 1 and order by highest review
.by(
__.inE("review")
.has("value", p.gte(1))
.order()
.by("value", queryOrder)
.valueMap(true)
.fold()
)
.limit(10)
.toList();
Thanks in advance for your answer!

Get cypress database query output objects in to variables

I have a cypress test which has been set up with mysql node module. When I run bellow mentioned test Its giving output as follows.
const executeQuery = (query) => {
cy.task('DBQuery', query).then(function (recordset) {
var rec = recordset
cy.log(rec)
})
}
Query:
select *
from Users
where email = 'sheeranlymited#lymitedtest.com'
OUTPUT: log [Object{23}]
Query:
select firstname
from Users
where email = 'sheeranlymited#lymitedtest.com'
OUTPUT: log [{firstname: Edward}]
instead of cy.log(rec) I want to get the output of 23 columns to assign in to different variables based on the column name.
Appreciate if someone can help me to resolve this...
You can use Object.values in js to retrieve values from your object
Let's say you need to extract the value of the 3rd column, so your code will look like,
cy.task('DBQuery', query).then(function (recordset) {
var rec = recordset
const results = Object.values(rec[0])
// results[index of the column] will output the results
cy.log(results[3])
})
We can do a small modification to make your task easier,
cy.task('DBQuery', query).then(function (recordset) {
var rec = recordset
const Values = Object.values(rec[0]);
const keys = Object.keys(rec[0]);
let result = {};
let index = 0;
keys.forEach(key => {
result[keys[index]] = Values[index];
i++
})
//result.firstName will give you your results
cy.log(result.firstName);
})
In this way, we are generating key-value pairs having the key as the column name. So you can use the column name to find the value.
Hope this helps.
cheers.

How to get rows from javascript array response?

I have skills in one table, user_skills in other table and getting skills against id from skills table in for loop.I have stored query results in javascript array. I want a array with objects in it. I'm getting array in array structure. As you can see in image that i am getting multiple arrays in array.It should be objects in single array.
var userExist = await ctx.app.pool.query("SELECT * FROM USER_SKILLS WHERE user_id = $1",
[`${user_id}`]);
var strArray = userExist.rows[0].skill_array.split(",");
var i;
var skillsArray = [];
for (i = 0; i < strArray.length; i++) {
var findSkill = await ctx.app.pool.query("SELECT skill_name FROM ALL_SKILLS WHERE id = $1",
[`${strArray[i]}`]);
skillsArray.push(findSkill.rows);
}
console.log('skillsArray', skillsArray);
ctx.body = {
status: 200,
error: false,
message: "Skills found",
data: skillsArray
};
Assuming skill_array is in fact an array in postgres, you can combine both those queries into one:
const query = "SELECT skill_name
FROM ALL_SKILLS
WHERE id = ANY((
SELECT skill_array
FROM USER_SKILLS
WHERE user_id = $1
))";
const res = await ctx.app.pool.query(query, [`${user_id}`]);
That will be more performant than doing multiple queries.
Then the reason why you're getting an array with arrays is because skillsArray.push(findSkill.rows) puts the whole rows property, which is an array, into your skillsArray array.
It's not entirely clear to me exactly what is the format of the result you want, but I'll assume it's the actual skill names in an array, something like:
{
message: "Skills found",
data: [
"PHP",
"Node js"
]
}
In which case you could restructure your code to be something like this:
const query = "SELECT STRING_AGG(skill_name, ',') AS skill_names
FROM ALL_SKILLS
WHERE id = ANY((
SELECT skill_array
FROM USER_SKILLS
WHERE user_id = $1
))";
const res = await ctx.app.pool.query(query, [`${user_id}`]);
const skillNames = res.rows[0].skill_names.split(',');
ctx.body = {
status: 200,
error: false,
message: "Skills found",
data: skillNames
};
I've added a STRING_AGG because I like to get postgres results in a single row if possible rather than have pg read multiple rows sequentially, I believe it will be faster. I'm not using ARRAY_AGG because I don't know how the pg module treats arrays, whether it converts them to string or a js array. So I return one field with the skills concatenated with a comma, e.g. "PHP,Node js", then just need to split that one field by the comma to get the desired array.
I believe this is what you want
var userExist = await ctx.app.pool.query("SELECT * FROM USER_SKILLS WHERE user_id = $1",
[`${user_id}`]);
var strArray = userExist.rows[0].skill_array.split(",");
var i;
var skillsArray = [];
for (i = 0; i < strArray.length; i++) {
var findSkill = await ctx.app.pool.query("SELECT skill_name FROM ALL_SKILLS WHERE id = $1",
[`${strArray[i]}`]);
skillsArray.push(findSkill.rows[0]);
}
console.log('skillsArray', skillsArray);
ctx.body = {
status: 200,
error: false,
message: "Skills found",
data: skillsArray
};
But I as i mentioned in my comment, I suggest that you have your database tables/schema in relationships M:M, in your case, where you can just get the data you need in a single query, and it is considered bad practice to do a query in for(...) loop like this. you should use ORM like Sequelize or any other ORM that you prefer and works well with KOA, I hope this help you in achieving this:

Parse.com match all pointers on array in given relation column

I have Conversation classes with a members relation attribute pointing to User class.
This members attribute consists of people belong to a particular conversation.
Now I want to query if given array of pointers User is part of particular conversation given that all elements must match.
I tried to use containsAll("members", users) but instead got undefined.
containedIn() worked but it returned all matching conversation that has at least one matching User in array.
equalTo("members", users) was not working as well and note that the users variable is array of pointers and not just array of strings objectId, but I also tried that one but got me nowhere.
Here's what I tried:
* Created AND queries where userRelationQuery.equalTo('member', ParseUser1) up to N number of users and still didn't work
Here's my solution but feel free to correct this for improvement
const members = getMembers();
let query = new Parse.Query("Conversation").equalTo(
"members",
members[0]
);
for (let i = 0; i < members.length; i++) {
query = new Parse.Query("Conversation")
.matchesKeyInQuery("objectId", "objectId", query)
.equalTo(
"members",
members[i]
);
}
const chat = await query.includeAll().first();
This should work for you
var conversationClass = Parse.Object.extend('Conversation');
var conversationQuery = new Parse.Query(conversationClass);
return conversationQuery.first()
.then(queryResult => {
var userRelationQuery = queryResult.relation('members').query(); //You can get all users releated to this conversation
//userRelationQuery.equalTo('username', 'Blank0330') // Or you can add more conditions
return userRelationQuery.find()
.then(users => {
return users; //This is your releated users
});
});
For more information about Parse-JS-SDK Relation

Get the actual array of rows from SQL query with sqlite and Expo

I am trying to get the whole result as array of rows from sqlite query results object:
I have tried results.rows.item(i).id and it work just fine but I need to get the whole array of rows instead of only one item, i tried to use rows.array (_number) from Expo documentation but I can't figure out how actually to use .array(_number)
my code snippet:
iris.transaction(tx => {
tx.executeSql(
`select id, date from days`,
[],
(tx, results) => {
for(i=0; i<results.rows.length; i++){
var date = results.rows.item(i).date.split('-');
}
}
)
});
As per the Expo document, the result.rows has an _array which returns all the items as array, you can try like
if (result && result.rows && result.rows._array) {
/* do something with the items */
// result.rows._array holds all the results.
}
Hope this will help!
TypeScript Solution to cast _array properly without using any ;)
tx.executeSql("SELECT * FROM ITEMS", [], (_, { rows }) => {
const r = rows as unknown as { _array: MyItem[] };
result = r._array;
});

Categories

Resources