Why my SQL response is undefined?(using mysql2/promise) - node.js

i want to pick my mysql response.
this is my code.
let [isTrue] = await conn.query("select user_key, isvalid from auth where user_key = ?", [user_key]);
console.log(isTrue);
This response was [ TextRow { user_key: '123445', isvalid: 1 } ]
That's good. But i want to get a value of user_key.
So I typed this code.
console.log(isTrue.user_key)
But this result was only undefined
How can i get a value of user_key??

instead of "await conn.query" use like this "await query".
Example
const mysql = require('mysql'); // or use import if you use TS
const util = require('util');
const conn = mysql.createConnection({host:"localhost", user:"root", password:"root", database:"test"});
// node native promisify
const query = util.promisify(conn.query).bind(conn);
(async () => {
try {
//const rows = await query('select count(*) as count from users ');
//console.log(rows);
var user_key = 1;
const [isTrue] = await query("select id,name from users where id = ?", [user_key]);
console.log(isTrue.name);
}
catch(err) {
throw new Error(err)
}
finally {
conn.end();
}
})();

Related

Firebase Function onCreate add to new collection works, but update does not

I have this onCreate Trigger, I am using it to aggregate and add record or update record. First it takes minutes to add the record and then the update never runs just keeps adding, not sure why my query is not bringing back a record to update.
Any suggestion would be great.
exports.updateTotals = functions.runWith({tinmeoutSeconds: 540})
.firestore.document("user/{userID}/CompletedTasks/{messageId}")
.onCreate(async (snap, context) => {
const mycompleted = snap.data();
const myuserid = context.params.userID;
console.log("USER: "+myuserid);
const mygroup = mycompleted.groupRef;
const myuser = mycompleted.userRef;
const newPoints = mycompleted.pointsEarned;
console.log("POINTS: "+newPoints);
const data = {
groupRef: mygroup,
userRef: myuser,
pointsTotal: newPoints,
};
const mytotalsref = db.collection("TaskPointsTotals")
.where("groupRef", "==", mygroup)
.where("userRef", "==", myuser);
const o = {};
await mytotalsref.get().then(async function(thisDoc) {
console.log("NEW POINTS: "+thisDoc.pointsTotal);
const newTotalPoints = thisDoc.pointsTotal + newPoints;
console.log("NEW TOTAL: "+newTotalPoints);
if (thisDoc.exists) {
console.log("MYDOC: "+thisDoc.id);
o.pointsTotal = newTotalPoints;
await mytotalsref.update(o);
} else {
console.log("ADDING DOCUMENT");
await db.collection("TaskPointsTotals").doc().set(data);
}
});
});
You are experiencing this behavior because while querying for updates you are getting more than 1 document and you are using thisDoc.exists on more than one document. If you have used typescript this could have been catched while writing the code.
So for the update query, if you are confident that only unique documents exist with those filters then here’s the updated code that I have recreated using in my environment.
functions/index.ts :
exports.updateTotals = functions.runWith({timeoutSeconds: 540})
.firestore.document("user/{userId}/CompletedTasks/{messageId}")
.onCreate(async (snap, context) => {
const mycompleted = snap.data();
const myuserid = context.params.userID;
console.log("USER: "+myuserid);
const mygroup = mycompleted.groupRef;
const myuser = mycompleted.userRef;
const newPoints = mycompleted.pointsEarned;
console.log("POINTS: "+newPoints);
const data = {
groupRef: mygroup,
userRef: myuser,
pointsTotal: newPoints,
};
const mytotalsref = admin.firestore()
.collection("TaskPointsTotals")
.where("groupRef", "==", mygroup)
.where("userRef", "==", myuser);
await mytotalsref.get().then(async function(thisDoc) {
if (!thisDoc.empty) { // check if the snapshot is empty or not
const doc = thisDoc.docs[0];
if(doc.exists){
const newTotalPoints = doc.data()?.pointsTotal + newPoints;
const id = doc.id;
await db.collection("TaskPointsTotals").doc(id).update({pointsTotal: newTotalPoints});
}
} else {
await db.collection("TaskPointsTotals").doc().set(data);
}
});
});
For more information about QuerySnapshot methods check this docs

Is there a way to promisify a pools 'connection.query' so that it isnt specific to one connection?

ideally id like to move the line out of the function entirely but the only way i know to do this is in the function itself. the 'poolConnection' seems to be of the type 'mysql.PoolConnection', so id assume the query function is something like 'mysql.PoolConnection.query', but i cant find any way to modify the 'query' without writing it like 'poolConnection.query', which ties it to that specific connection. it seems like there should be a easy way to do this.
const discord = require('discord.js');
const config = require('./config.json');
var mysql = require('mysql');
const util = require('util');
const client = new discord.Client();
connection.connect(function(err) {
if (err) throw err;
client.login(config.token);
});
client.on('message', message => test());
let pool = mysql.createPool(poolConfig);
const getPoolConnection = util.promisify(pool.getConnection).bind(pool);
const endPool = util.promisify(pool.end).bind(pool);
async function test()
{
try
{
let poolConnection = await getPoolConnection();
//can the follow line be made so its not specific to one connection in the pool?
poolConnection.query = util.promisify(poolConnection.query);
let sql = `INSERT INTO user(UserID) VALUES(${01});`;
let sql2 = `INSERT INTO user(UserID) VALUES(${02});`;
await poolConnection.beginTransaction();
let results = await poolConnection.query(sql);
let results2 = await poolConnection.query(sql2);
await poolConnection.commit();
await poolConnection.release();
await endPool();
console.log(results);
console.log(results2);
}
catch(error)
{
console.log(error);
}
}

Parameter obj to Document() must be an object when trying to convert array to mongoose document with redis

I have using redis to cache my queries. Its working fine with object but not when i get array. It gives me an error **"Parameter "obj" to Document() must be an object, got kids", **. It also happens with count query. Here is my code :
const mongoose = require("mongoose");
const redis = require("redis");
const util = require("util");
const client = redis.createClient(process.env.REDIS_URL);
client.hget = util.promisify(client.hget);
const exec = mongoose.Query.prototype.exec;
mongoose.Query.prototype.cache = async function (options = {}) {
this.useCache = true;
this.hashKey = JSON.stringify(options.key || "");
this.time = JSON.stringify(options.time || 36000);
return this;
};
mongoose.Query.prototype.exec = async function () {
if (!this.useCache) {
return exec.apply(this, arguments);
}
const key = JSON.stringify(
Object.assign({}, this.getQuery(), {
collection: this.mongooseCollection.name,
})
);
// client.flushdb(function (err, succeeded) {
// console.log(succeeded); // will be true if successfull
// });
const cacheValue = await client.hget(this.hashKey, key);
if (cacheValue) {
const doc = JSON.parse(cacheValue);
/*
this.model refers to the Class of the corresponding Mongoose Model of the query being executed, example: User,Blog
this function must return a Promise of Mongoose model objects due to the nature of the mongoose model object having other
functions attached once is created ( validate,set,get etc)
*/
console.log("Response from Redis");
console.log(doc);
console.log(Array.isArray(doc));
return Array.isArray(doc)
? doc.map((d) => new this.model(d))
: new this.model(doc);
}
//await the results of the query once executed, with any arguments that were passed on.
const result = await exec.apply(this, arguments);
client.hset(this.hashKey, key, JSON.stringify(result));
client.expire(this.hashKey, this.time);
console.log("Response from MongoDB");
return result;
};
module.exports = {
clearHash(hashKey) {
client.del(JSON.stringify(hashKey));
},
};
Data in redis - [ 'kids', 'men', 'women' ]
Query - const collectionType = await Product.find() .distinct("collectionType") .cache({ key: "COLLECTION_TYPE" });
can i anyone please tell me what i am doing wrong?
I have solved by directly returning the doc and its working fine. Not sure if it is the right way if i directly do return doc then sending data from redis only

Can I use #google-cloud/logging Node.js library to getEntries filtering by date?

I've got this code to getEntries from my project's cloud-logging.
import { Logging } from "#google-cloud/logging";
const PROJECT_ID = "XXXXX";
const logging = new Logging({ projectId: PROJECT_ID });
const getAdminLogEntries = async () => {
const result = await logging.getEntries({
filter: `logName="projects/XXXXX/logs/my-custom-log-name"`,
});
const entryList = result[0];
for (const entry of entryList) {
console.log(`entry.metadata: ${JSON.stringify(entry.metadata)}`);
console.log(`entry.data: ${JSON.stringify(entry.data)}`);
console.log(`---`);
}
};
getAdminLogEntries();
But I'm only getting 6 results (the oldest one is from yesterday). And I guess it's because the query is not going too far back in time. Can it filter it by date? Ex: from 2021-01-01 to 2021-01-31?
Here is what I've found out.
Reference:
https://cloud.google.com/logging/docs/view/advanced-queries
https://cloud.google.com/logging/docs/reference/libraries#list_log_entries
I was able to filter by date with the following code:
import { Logging } from "#google-cloud/logging";
const PROJECT_ID = "XXXX";
const logging = new Logging({ projectId: PROJECT_ID });
const filterItems = [
`logName="projects/XXXXX/logs/admin-logs"`,
`timestamp >= "2021-02-01T00:00:00Z"`,
`timestamp < "2021-03-01T00:00:00Z"`,
`severity="WARNING"`,
];
// JOINING FILTERS WITH "AND" OPERATOR
const filters = filterItems.join(" AND ");
const getAdminLogEntries = async () => {
const result = await logging.getEntries({
filter: filters,
});
const entryList = result[0];
for (const entry of entryList) {
console.log(`entry.metadata.severity: ${JSON.stringify(entry.metadata.severity)}`);
console.log(`entry.metadata.timestamp: ${JSON.stringify(entry.metadata.timestamp)}`);
console.log(`entry.data.message: ${JSON.stringify(entry.data.message)}`);
console.log(`---`);
}
};
getAdminLogEntries();

pool.request is not a function

I would like to setup my prepared statements with the mssql module. I created a query file for all user related requests.
const db = require('../databaseManager.js');
module.exports = {
getUserByName: async username => db(async pool => await pool.request()
.input('username', dataTypes.VarChar, username)
.query(`SELECT
*
FROM
person
WHERE
username = #username;`))
};
This approach allows me to require this query file and access the database by executing the query that is needed
const userQueries = require('../database/queries/users.js');
const userQueryResult = await userQueries.getUserByName(username); // call this somewhere in an async function
My database manager handles the database connection and executes the query
const sql = require('mssql');
const config = require('../config/database.js');
const pool = new sql.ConnectionPool(config).connect();
module.exports = async request => {
try {
const result = await request(pool);
return {
result: result.recordSet,
err: null
};
} catch (err) {
return {
result: null,
err
}
}
};
When I run the code I get the following error
UnhandledPromiseRejectionWarning: TypeError: pool.request is not a
function
Does someone know what is wrong with the code?
I think this happens because the pool is not initialized yet... but I used async/await to handle this...
Here is how I made your code work (I did some drastic simplifications):
const sql = require("mssql");
const { TYPES } = require("mssql");
const CONN = "";
(async () => {
const pool = new sql.ConnectionPool(CONN);
const poolConnect = pool.connect();
const getUserByName = async username => {
await poolConnect;
try {
const result = await pool.request()
.input("username", TYPES.VarChar, username)
.query(`SELECT
*
FROM
person
WHERE
username = #username;`);
return {
result: result.recordset,
err: null
};
} catch (err) {
return {
result: null,
err
};
}
};
console.log(await getUserByName("Timur"));
})();
In short, first read this.
You probably smiled when saw that the PR was created just 2 months before your questions and still not reflected in here.
Basically, instead of:
const pool = new sql.ConnectionPool(config).connect();
you do this:
const pool = new sql.ConnectionPool(config);
const poolConnection = pool.connect();
//later, when you need the connection you make the Promise resolve
await poolConnection;

Resources