I have a problem with fetching specific columns from the database. I want to fetch balance for a user with provided user_id and currency.
And I'm getting >[ { '?column?': 'USD' } ] for provided currency = 'USD', instead of [ {'USD': 1.2}]. And when I don't use column name then I'm fetching whole balances for a user.
The table is looking something like this:
user_id | USD | EUR | GBP | ...
123123 1.2 2.3 3.4
(Balances for that user in that currency), so for user 123123, his USD balance is 1.2, EUR is 2.3 and GBP is 3.4
import dotenv from 'dotenv';
import pkg from 'pg';
dotenv.config();
const {Pool, Client} = pkg
const DB_USER = process.env.DB_USER;
const DB_HOST = process.env.DB_HOST;
const DB_DATABASE = process.env.DB_DATABASE;
const DB_PASSWORD = process.env.DB_PASSWORD;
const DB_PORT = process.env.DB_PORT;
const credentials = {
user: DB_USER,
host: DB_HOST,
database: DB_DATABASE,
password: DB_PASSWORD,
port: DB_PORT,
};
async function getBalance(user_id, currency) {
const pool = new Pool(credentials);
const res = await pool.query('SELECT $1 FROM wallet WHERE user_id = $2;', [currency, user_id]);
console.log(res.rows);
await pool.end();
}
You cannot parameterise a column name, you'll need to build the SQL string dynamically for that:
async function getBalance(user_id, currency) {
const client = new Client(credentials);
await client.connect();
const query = 'SELECT '+client.escapeIdentifier(currency)+' FROM wallet WHERE user_id = $1;';
const res = await client.query(query, [user_id]);
console.log(res.rows);
await client.end();
}
You might also want to validate the currency names to be existing columns (and not 'user_id'), like
if (!['USD', 'EUR', 'GBP'].includes(currency)) throw new RangeError('Currency not available');
Related
``I workk with stellar network , I create an account with stellar laboratry and node.js,in the begin I save the data in Json file and everything works perfectly but now I want to save it into the database, the signup function work correctly but when I try to check the balance account I am bloked and I have Errors
So my question : I want to use the publickey from the user_account in the database and check the balance using Stellar Horizen
How can I do it ?``
enter image description here
This is the data for the user when he sign up
**SignUp function **
const userModel= require('../models/user.model')
const { errorsSignUp,errorsSignIn } = require('../utils/errors')
const stellar = require("stellar-sdk");
module.exports.signUp= async(req,res)={
const {pseudo,email,password}= req.body
try{
const pair = stellar.Keypair.random();
const userData= await userModel.create(
{
pseudo,
email,
password,
publicKey: pair.publicKey(),
secret:pair.secret(),
})
// await userData.save()
res.send(userData)
res.status(201).json({userData:userData._id})`
}
catch(err){
const errors= errorsSignUp(err)
res.status(200).send({errors})
}
}
Check balance function
const stellar= require('stellar-sdk')
const accounts= require("./accounts")
const util = require("util")
//const userModel = require('../models/user.model')
// function without mongodb
// saving data in file.json
var server= new stellar.Server("https://horizon-testnet.stellar.org")
const checkAccount= async accounts={
const AccountsBalance= await Promise.all(
accounts.map(async account= await server.loadAccount(account.publicKey)))
return AccountsBalance.map(({id,balances})=({
id,
balances,
}))
}
checkAccount(accounts)
.then(account=
console.log(util.inspect(account,false, null))
)
.catch(error={
console.log(error)
})
I have created the following user schema, including two methods:
getSnapshot()
getLastTweetId()
user.js
const mongoose = require('mongoose')
const getLastTweetId = require('../utilities/getLastTweetId')
const getFollowers = require('../utilities/getFollowers')
const userSchema = new mongoose.Schema({
twitterId: {
type: String,
required: true
},
screenName: {
type: String
},
snapshots: {
type: [snapshotSchema],
default: []
},
createdAt: {
type: Date
},
})
userSchema.method('getSnapshot', async function () {
const { user, snapshot } = await getFollowers({user: this})
await user.save()
return snapshot
})
userSchema.method('getLastTweetId', async function () {
const tweetId = await getLastTweetId({user: this})
return tweetId
})
const User = mongoose.model('User', userSchema)
module.exports = User
When I define a user instance in passport.js, I can call getSnapshot() on user with no problems. (see below)
passport.js
const passport = require('passport')
const mongoose = require('mongoose')
const needle = require('needle')
const { DateTime } = require('luxon')
const User = mongoose.model('User')
// Setup Twitter Strategy
passport.use(new TwitterStrategy({
consumerKey: process.env.TWITTER_CONSUMER_API_KEY,
consumerSecret: process.env.TWITTER_CONSUMER_API_SECRET_KEY,
callbackURL: process.env.CALLBACK_URL,
proxy: trustProxy
},
async (token, tokenSecret, profile, cb) => {
const twitterId = profile.id
const screenName = profile.screen_name
const existingUser = await User.findOne({ twitterId })
if (existingUser) {
// Track if this is a new login from an existing user
if (existingUser.screenName !== screenName) {
existingUser.screenName = screenName
await existingUser.save()
}
// we already have a record with the given profile ID
cb(undefined, existingUser)
} else {
// we don't have a user record with this ID, make a new record
const user = await new User ({
twitterId ,
screenName,
}).save()
**user.getSnapshot()**
cb(undefined, user)
}
}
)
However, when I call getLastTweetId() on a user instance in tweet.js, I receive the following error in my terminal:
TypeError: user.getLastTweetId is not a function
Then my app crashes.
tweets.js
const express = require('express')
const mongoose = require('mongoose')
const User = mongoose.model('User')
const Tweet = mongoose.model('Tweet')
const { DateTime } = require('luxon')
const auth = require('../middleware/auth')
const requestTweets = require('../utilities/requestTweets')
const router = new express.Router()
const getRecentTweets = async (req, res) => {
const twitterId = req.user.twitterId
const user = await User.find({twitterId})
*const sinceId = user.getLastTweetId()*
let params = {
'start_time': `${DateTime.now().plus({ month: -2 }).toISO({ includeOffset: false })}Z`,
'end_time': `${DateTime.now().toISO({ includeOffset: false })}Z`,
'max_results': 100,
'tweet.fields': "created_at,entities"
}
if (sinceId) {
params.since_id = sinceId
}
let options = {
headers: {
'Authorization': `Bearer ${process.env.TWITTER_BEARER_TOKEN}`
}
}
const content = await requestTweets(twitterId, params, options)
const data = content.data
const tweets = data.map((tweet) => (
new Tweet({
twitterId,
tweetId: tweet.id,
text: tweet.text,
})
))
tweets.forEach(async (tweet) => await tweet.save())
}
// Get all tweets of one user either since last retrieved tweet or for specified month
router.get('/tweets/user/recent', auth, getRecentTweets)
module.exports = router
I would really appreciate some support to figure out what is going on here.
Thank you for bearing with me!
My first guess was that the user instance is not created properly in tweets.js, but then I verified via log messages that the user instance is what I expect it to be in both passport.js as well as tweets.js
My second guess was that the problem is that the user instance in the database was created before I added the new method to the schema, but deleting and reinstantiating the entire collection in the db changed nothing.
Next I went about checking if the issue is related to instantiating the schema itself or just importing it and it seems to be the latter, since when I call getLastTweetId in passport.js it also works, when I call getSnapshot() in tweets.js it also fails.
This is where I'm stuck, because as far as I can tell, I am requiring the User model exactly the same way in both files.
Even when I print User.schema.methods in either file, it shows the following:
[0] {
[0] getSnapshot: [AsyncFunction (anonymous)],
[0] getLastTweetId: [AsyncFunction (anonymous)]
[0] }
It looks like my first guess regarding what was wrong was on point, and I was just sloppy in verifying that I'm instantiating the user correctly.
const user = await User.find({twitterId})
The above line was returning an array of users.
Instead, I should have called:
const user = await User.findOne({twitterId})
I did not detect the bug at first, because logging an array that contains only one object looks nearly the same as just logging the object itself, I simply overlooked the square brackets.
Changing that single line fixed it.
I have a peculiar problem. I have a joined query due to the distribution of data in various table. I want to run this as raw sql query using node module for sequelize as alot existing code is associated using sequelize orm. I do not want to use orm here but just a plain raw query.
SELECT testmodel.bacode, testmodel2.paopkey from (SELECT ptr.paopkey as paopkey, psgkey.pskey from (SELECT * FROM pts where paopkey = 4 and ptr_active = 1) ptr,
pt_sg psgkey where ptr.pkey = psgkey.pkey) testmodel2,
pt_act testmodel where testmodel.pskey = testmodel2.pskey;
Any advise if the above query can be run as raw query and the data can be captured as result.
Also when I run the below code with below sequelize code, I get
the error "_sequelize.default.query is not a function"
import Sequelize from 'sequelize';
async function getTestDataList(opcoKey) {
const testdata = await Sequelize.query(`SELECT testmodel.bacode, testmodel2.paopkey from (SELECT ptr.paopkey as paopkey, psgkey.pskey from (SELECT * FROM pts where paopkey = 4 and ptr_active = 1) ptr,
pt_sg psgkey where ptr.pkey = psgkey.pkey) testmodel2,
pt_act testmodel where testmodel.pskey = testmodel2.pskey;`,
{ type: Sequelize.QueryTypes.SELECT }).then(function (results) {
// SELECT query - use then
})
return toPlain(testdata);
}
Dbclient code using sequelize instance is as follows
import config from 'config';
import Sequelize from 'sequelize';
class DataSource { constructor() {this.DBclient = null; }
initializeDB(dbCredentials) { const dataSource = config.datasource;
const options = { host: "127.0.0.1", dialect: dataSource.dialect, port: dataSource.port, logging: false, };
const { password } = dbCredentials || dataSource;
this.DBclient = new Sequelize( dataSource.database, "root", "root", options, );
} getDBClient() { return this.DBclient; }}export default new DataSource();
You should store a created Sequelize connection and use it to call query method:
const sequelize = new Sequilize(connection_options_here)
const testdata = await sequelize.query(`SELECT testmodel.bacode, testmodel2.paopkey from (SELECT ptr.paopkey as paopkey, psgkey.pskey from (SELECT * FROM pts where paopkey = 4 and ptr_active = 1) ptr,
pt_sg psgkey where ptr.pkey = psgkey.pkey) testmodel2,
pt_act testmodel where testmodel.pskey = testmodel2.pskey;`,
{ type: Sequelize.QueryTypes.SELECT })
I removed then in the above code because there is no need in it thus you use await.
I have a route and I want it to send two primary keys as foreign keys to my orderline table. I have three tables a customer, address and orderline table. an orderline has one customer and one address as foreign keys. I´m really struggling to figure it out. My route looks like this:
import express from "express";
import expressAsyncHandler from 'express-async-handler';
import { isAuth } from '../utlis';
import {Orderline, Address} from '../models';
const orderRouter = express.Router();
orderRouter.post(
'/',
isAuth,
expressAsyncHandler(async (req, res) => {
const customerId = req.customer.id;
const addresss = Address.findOne({where: {CustomerId: customerId}})
const addressId = addresss.id
const createdOrder = ({
totalPrice: req.body.totalPrice,
itemsPrice: req.body.itemsPrice,
taxPrice: req.body.taxPrice,
shippingPrice: req.body.shippingPrice,
AddressId: addressId,
CustomerId: customerId
});
Orderline.create(createdOrder);
res.status(201).send({ message: 'New Order Created', data: createdOrder});
})
);
export default orderRouter;
As seen in the code I have attempted to retrieve the address that has the id of the user logged in and then gett the ID and send that as the value. I would ideally like to find the postcode,address and customerID in the address table and Any help/guidance is much appreciated.
First, you need to indicate await to the left from 'findOne' and create because they are async functions and you want to get the result in the calling code:
const customerId = req.customer.id;
const address = req.address;
const postcode = req.postcode;
const addresss = await Address.findOne({
where: {
CustomerId: customerId,
address: address,
postcode: postcode
}
})
const addressId = addresss.id
const createdOrder = ({
totalPrice: req.body.totalPrice,
itemsPrice: req.body.itemsPrice,
taxPrice: req.body.taxPrice,
shippingPrice: req.body.shippingPrice,
AddressId: addressId,
CustomerId: customerId
});
const newOrder = await Orderline.create(createdOrder);
// in case you want to send the whole orderline object along with its generated ID
res.status(201).send({ message: 'New Order Created', data: newOrder});
And if you don't indicate attributes option in findOne you will get all attributes of Address.
Im using v6.3.1 of node mssql.
My query includes multiple columns of the type date.
In node mssql the output of all Date columns are in the format: 2020-10-20T00:00:00.000Z
When I make the same query in Azure Data Studio I get: 2020-10-20
My problem is when I need to update the database as I get an error using the YYYY-MM-DD format.
is there a way to update the database without having to check each field if its a date and then add "0T00:00:00.000Z" to it?
Current code is this:
// Runs at server startup
const sql = require('mssql')
const poolPromise = sql.connect({
server: process.env.SQL_SERVER,
user: process.env.SQL_USER,
password: process.env.SQL_PASSWORD,
database: process.env.SQL_DATABASE
})
// Runs at query
async function updateSqlRecord(fields) {
// Adding fields below for demonstration
let fields = {id: 1, name: 'test', date: '2020-10-12' }
let database = process.env.SQL_DATABASE
let table = 'Test'
let querystring = `UPDATE [${database}].[dbo].[${table}] SET `
Object.entries(fields).forEach(field => {
const [key, value] = field;
querystring += `${key} = '${value}', `
});
querystring = querystring.slice(0, -2)
querystring += ` WHERE projektNr = ${fields.projektNr}`
try {
let pool = await poolPromise
let result = await pool.request()
// .input('projektNr', sql.Int, value)
.query(querystring)
console.log(result)
return result.rowsAffected
} catch (err) {
console.log('SQL request Error',err)
}
}
If possible you could try to use moment.js to parse the date before adding it to the database
var moment = require('moment');
...
var formatedDate = moment(myDate).format('YYYY/MM/DD HH:MM:SS').toISOString();