TypeORM createQueryBuilder: Is possible to use table name as string instead of entity - javascript

In my current scenario, a third party will be creating tables dynamically on my DB, and storing the table name as a varchar and column names as jsonb in other table which is defined as an Entity in my NestJS backend.
This is so I can keep track (and query) these tables, since I have no control over its creation.
For this purpose I'd like to use TypeORM's createQueryBuilder instead of using raw queries as its easier for me to play with abstraction.
As far as I know TypeORMs createQueryBuilder needs a defined Entity in the from clause.
Something like this:
return await getManager()
.createQueryBuilder()
.select('*')
.from(MyDefinedModel, 'modelAlias')
.getRawMany();
}
So I'd like to do something like:
const tableName = await getDynamicallyGenetaredTableNames().getFirstOne()
// now tableName points to a string that is a table name, i.e 'table-data-192239'
return await getManager()
.createQueryBuilder()
.select('*')
.from(tableName, 'tableAlias')
.getRawMany();
So passing the table name I point to the right table, but TypeORM (and TS) complains because that tableName is a string, and not an Entity (Class) type
I really don't want to type-cast and start doing nasty things if there is something cleaner to achieve this.
I didn't find any solution in the official docs
Any brilliant ideas out there?
Thanks, y'all

We can pass table name instead of Entity for getRepository.
let tableName = 'user';
let query = getRepository(tableName).createQueryBuilder(tableName);

You can select from a table by its table name without defining an entity before like this:
const res = await manager
.createQueryBuilder()
.select()
.from("tableName", null)
.where("tableName.id = :id", { id: 1 })
.getRawMany();
Be sure that you set the second parameter of the from() explicitly to null.

You could try using a raw query:
import { getManager } from 'typeorm'
const tableName = await getDynamicallyGenetaredTableNames().getFirstOne()
// Use the table name in a raw SQL query
const result = await getManager().query(`SELECT * FROM ${tableName}`)

Related

How can I use DEFAULT values via knex insert?

My goal is to dynamically insert data into a table via knex.
Code looks like this:
const knexService = require("../knexService.js")
async function insertObjectToKnex() {
const insertObject = {
id: "DEFAULT",
someKey: "someValue"
};
await knexService.db("table").insert(inserObject);
}
On DEFAULT the next free id should be used as database id - table is configured and it works with raw sql. With knex.js I get the following error:
invalid input syntax for type integer: "DEFAULT"
Using the useNullAsDefault: true, config is not possible, because the id is not nullable.
How can I trigger the default value in knex - I did not find anything in the documentation or with google, that could at least give a hint to this issue!
While it is not mentioned in the documentation of knex.js one should simply not add fields with a DEFAULT assignement to a query. This will set the default value to the row column.

How do I prevent sql injection on a WHERE IN request with parameterized query? [duplicate]

I am trying to workout how to pass in a comma sepated string of values into a postgres select within in clause query using node-postgres but unfortunately can't seem to get it working and can't find any examples.
I have the following code:
function getUser() {
let inList = "'qwerty', 'qaz'";
const result = await pgPool.query("SELECT name FROM my_table WHERE info IN ($1)", [inList]);
if (result.rowCount == 1) return result.rows.map(row => row.name)
return false
}
Basically want the end result query to process:
SELECT name FROM my_table WHERE info IN ('qwerty', 'qaz')
Unsure if this is actually the correct way of doing this with pgPool?
The right way is in the FAQ on Github --> https://github.com/brianc/node-postgres/wiki/FAQ#11-how-do-i-build-a-where-foo-in--query-to-find-rows-matching-an-array-of-values
You should be able to do it that way :
pgPool.query("SELECT name FROM my_table WHERE info = ANY ($1)", [jsArray], ...);

get records after creation using sequelize raw query

I am using sequelize for migration. here I execute an INSERT query with following options but its didnot return created records:
const res = oldUsers.map(u => sequelize.query(
`INSERT INTO ${LP_LOCATIONS_TABLE} (name, address, city)
VALUES (
'${u.email}', '${u.address}', '${u.city}');`,
{ type: DataTypes.QueryTypes.INSERT, raw: true },
))
the output is an array of array like below:
[ [[0],[1]] ]
i expect to get created recorders. specially PK. how can I fix it?
I forgot to put RETURNING * at the end of the raw SQL query.
From the doc, you may have to specify the option returning:true to make this happen. I use mySql, so can't test (the returning option is only for postgres).

Select all the fields in a mongoose schema

I want to obtain all the fields of a schema in mongoose. Now I am using the following code:
let Client = LisaClient.model('Client', ClientSchema)
let query = Client.findOne({ 'userclient': userclient })
query.select('clientname clientdocument client_id password userclient')
let result = yield query.exec()
But I want all the fields no matter if they are empty. As always, in advance thank you
I'm not sure if you want all fields in a SQL-like way, or if you want them all in a proper MongoDB way.
If you want them in the proper MongoDB way, then just remove the query.select line. That line is saying to only return the fields listed in it.
If you meant in a SQL-like way, MongoDB doesn't work like that. Each document only has the fields you put in when it was inserted. If when you inserted the document, you only gave it certain fields, that document will only have those fields, even if other documents in other collections have different fields.
To determine all available fields in the collection, you'd have to find all the documents, loop through them all and build an object with all the different keys you find.
If you need each document returned to always have the fields that you specify in your select, you'll just have to transform your object once it's returned.
const fields = ['clientname', 'clientdocument', 'client_id', 'password', 'userclient'];
let Client = LisaClient.model('Client', ClientSchema)
let query = Client.findOne({ 'userclient': userclient })
query.select(fields.join(' '))
let result = yield query.exec()
fields.forEach(field => result[field] = result[field]);
That forEach loop will set all the fields you want to either the value in the result (if it was there) or to undefined if it wasn't.
MongoDB is schemaless and does not have tables, each collection can have different types of items.Usually the objects are somehow related or have a common base type.
Retrive invidual records using
db.collectionName.findOne() or db.collectionName.find().pretty()
To get all key names you need to MapReduce
mapReduceKeys = db.runCommand({
"mapreduce": "collection_name",
"map": function() {
for (var key in this) {
emit(key, null);
}
},
"reduce": function(key, stuff) {
return null;
},
"out": "collection_name" + "_keys"
})
Then run distinct on the resulting collection so as to find all the keys
db[mapReduceKeys.result].distinct("_id") //["foo", "bar", "baz", "_id", ...]

Mongoose: multiple query populate in a single call

In Mongoose, I can use a query populate to populate additional fields after a query. I can also populate multiple paths, such as
Person.find({})
.populate('books movie', 'title pages director')
.exec()
However, this would generate a lookup on book gathering the fields for title, pages and director - and also a lookup on movie gathering the fields for title, pages and director as well. What I want is to get title and pages from books only, and director from movie. I could do something like this:
Person.find({})
.populate('books', 'title pages')
.populate('movie', 'director')
.exec()
which gives me the expected result and queries.
But is there any way to have the behavior of the second snippet using a similar "single line" syntax like the first snippet? The reason for that, is that I want to programmatically determine the arguments for the populate function and feed it in. I cannot do that for multiple populate calls.
After looking into the sourcecode of mongoose, I solved this with:
var populateQuery = [{path:'books', select:'title pages'}, {path:'movie', select:'director'}];
Person.find({})
.populate(populateQuery)
.execPopulate()
you can also do something like below:
{path:'user',select:['key1','key2']}
You achieve that by simply passing object or array of objects to populate() method.
const query = [
{
path:'books',
select:'title pages'
},
{
path:'movie',
select:'director'
}
];
const result = await Person.find().populate(query).lean();
Consider that lean() method is optional, it just returns raw json rather than mongoose object and makes code execution a little bit faster! Don't forget to make your function (callback) async!
This is how it's done based on the Mongoose JS documentation http://mongoosejs.com/docs/populate.html
Let's say you have a BookCollection schema which contains users and books
In order to perform a query and get all the BookCollections with its related users and books you would do this
models.BookCollection
.find({})
.populate('user')
.populate('books')
.lean()
.exec(function (err, bookcollection) {
if (err) return console.error(err);
try {
mongoose.connection.close();
res.render('viewbookcollection', { content: bookcollection});
} catch (e) {
console.log("errror getting bookcollection"+e);
}
//Your Schema must include path
let createdData =Person.create(dataYouWant)
await createdData.populate([{path:'books', select:'title pages'},{path:'movie', select:'director'}])

Categories

Resources