TypeORM select alias of column name - mysql

this.sampleRepo.find(
{
order: {
id: "DESC"
},
select: ['id','group']
}
);
this returns the id and group as expected, but how to return id as user_id ?
and also how to select distinct values from group?

Just add an alias in you select string, e.g.:
select: ['id AS user_id','group AS user_group']
If the previous option didn't work, it should work in queryBuilder:
this.sampleRepo
.createQueryBuilder('user')
.orderBy('user.id', 'DESC')
.select(['id AS user_id','group AS user_group'])
.getRawMany() // or .getMany()
I've made smth as you need with one of my examples (last one here) but wrote this (upd. fixed with getRawMany and distinct):
getMany(): Promise<UserEntity[]> {
return this.userRepo.createQueryBuilder('user')
.where({ username: 'breckhouse0' })
.select(['DISTINCT (user.username) AS user_name', 'user.id AS user_id'])
.getRawMany();
}
and this works as you expect - results

Related

How do I order records not matched in leftJoin?

I'm new to Laravel and having a problem returning my results from this query in the correct order. I have a $products variable that contains both "A" and "B" type of products.
I'm doing a leftJoin with a match_products table to order the records by match_products.sku, but only "B" records are contained in that table.
$products = $products->with(['matches' => function ($quer) use ($business) {
$quer->where('user_id', $business->user_id)->with('skuDiscount');
}])->withCount(['variations' => function ($q) use ($business) {
$q->whereHas('seller_variations', function ($qu) use ($business) {
$qu->where('user_id', $business->user_id);
});
}])->leftJoin('match_products', function ($join) use ($business) {
$join->on('products.id', '=', 'match_products.product_id')
->where('match_products.user_id', '=', $business->user_id);
})
->orderBy('match_products.sku', $order)
->select('products.*')
->limit($perPage)
->offset($perPage * ($page - 1))
->get();
return response()->json(['products' => $products, 'productsCount' => $productsCount]);
My results are coming out:
A records
B records (in order by Sku)
but I need them to be the opposite:
B records (in order by Sku)
A records
I assume this is because the leftJoin is returning the matched records after the non-matched records but I need to return them before the non-matched records. I'd appreciate any help someone could please give me.

Laravel: get models if count of relation has some condition

I have User and UserComplains Models.
I like to retrieve users that have UserComplains more than 2 times in the last 24 hours.
users:
id
user_complains:
complained_id ->ref-> users.id
created_at
this is what I tried and it is working:
$users = User::select('users.*')->join('user_complains' , 'users.id' , '=' , 'user_complains.complained_id')
->whereRaw("(
select count(*) from `user_complains`
where `user_complains`.`complained_id` = `users`.`id`
and `user_complains`.`created_at` > ?) >= ?" , [now()->subHours(24), 2])
->groupBy("users.id")
->get();
the above code is fine and is working, but I wonder is there a better way to do that?!
For something like this you can use whereHas(). :
$users = User::whereHas('*relationship*', function ($query) {
$query->where('created_at', '>=', now()->subDay(1));
}, '>', 2)->get();
As mentioned in the documentation, you can pass additional checks as the 3rd and 4th param so in this case you want to say where the user has more that 2 user_complains.
NB You will need to replace *relationship* with the actual name of the relationship.
You can do the following:
User::whereHas('complaints', function($query) {
$query->where('created_at', '>=', '2020-04-26');
}, '>', 2)->get();
In order for this to work though you need to have set up a relationship between your User and UserComplaint models.
class User extends Model
{
public function complaints()
{
return $this->hasMany(UserComplaint:class);
}
}

rewrite left outer join for sub queries in bookshelf.js

Note : I have not shared database schema as I am mainly looking for a help only w.r.t. last step which is 'left outer join' on 2 sub-queries.
select *
from
(select id
from Action
where id = 3) AS act1
left Outer Join
(select Action.name,
completed_At as completedAt,
deadline, notes,
ActionAssignedTo.action_Id as actionId,
from Action
inner join Employee
on Action.created_By_Id = Employee.id
and Employee.vendor_Id = 2
inner join ActionAssignedTo
on Action.id = ActionAssignedTo.action_Id
and ActionAssignedTo.action_Id = 3
where Action.created_By_Id = 7
group by Action.id
limit 2) AS act2
on act1.id = act2.actionId
I need to write this above query using Bookshelf
let options = {columns: [ 'Action.name', 'completed_At as completedAt',
'deadline', 'notes',
'ActionAssignedTo.action_Id as actionId',
]};
let action2 = new Action();
action2.query().innerJoin('Employee', function () {
this.on('Action.created_By_Id', 'Employee.id')
.andOn('Employee.vendor_Id', bookshelf.knex.raw(1));
});
action2.query().innerJoin('ActionAssignedTo', function () {
this.on('Action.id', 'ActionAssignedTo.action_Id')
.andOn('ActionAssignedTo.action_Id', bookshelf.knex.raw(5));
});
action2.query().where(function() {
this.where('Action.created_By_Id', empId)
});
action2.query().groupBy('Action.id');
action2.query().limit(2);
action2.query().columns(options.columns);
let action1;
action1 = Action.where('id', actionId);
action1.query().columns('id');
return bookshelf.knex.raw('select * from '
+ '(' + action1.query().toString() + ') AS act1'
+ ' left Outer Join '
+ '(' + action2.query().toString() + ') AS act2'
+ ' on act1.id = act2.actionId');
I am not keen on using bookshelf.knex.raw for using the left Outer Join as the output given by knex.raw and bookshelf differ.
Is there a way I can do the 'left Outer Join' directly using bookshelf library.
I looked into the code but it seems leftOuterJoin only takes table name as the first parameter and what I need is a query.
I think your main problem is that you're using Bookshelf like you would be using knex. Bookshelf is meant to be used with models you would define and then query on them.
Here is an example of what you should have as model
// Adding registry to avoid circular references
// Adding camelcase to get your columns names converted to camelCase
bookshelf.plugin(['bookshelf-camelcase', 'registry']);
// Reference: https://github.com/brianc/node-pg-types
// These two lines convert all bigint values coming from Postgres from JS string to JS integer.
// Removing these lines will mess up with Bookshelf count() methods and bigserial values
pg.types.setTypeParser(20, 'text', parseInt);
const Action = db.bookshelf.Model.extend({
tableName: 'Action',
createdBy: function createdBy() {
return this.belongsTo(Employee, 'id', 'created_By_Id');
},
assignedTo: function assignedTo() {
return this.hasMany(ActionAssignedTo, 'action_id');
},
});
const Employee = db.bookshelf.Model.extend({
tableName: 'Employee',
createdActions: function createdActions() {
return this.hasMany(Action, 'created_By_Id');
},
});
const ActionAssignedTo = db.bookshelf.Model.extend({
tableName: 'ActionAssignedTo',
action: function action() {
return this.belongsTo(Action, 'id', 'action_Id');
},
employee: function employee() {
return this.belongsTo(Employee, 'id', 'employee_Id');
},
});
module.exports = {
Action: db.bookshelf.model('Action', Action),
Employee: db.bookshelf.model('Employee', Employee),
ActionAssignedTo: db.bookshelf.model('ActionAssignedTo', ActionAssignedTo),
db,
};
You would then be able to fetch your results with a query like this
const Model = require('model.js');
Model.Action
.where({ id: 3 })
.fetchAll({ withRelated: ['createdBy', 'assignedTo', 'assignedTo.employee'] })
.then(data => {
// Do what you have to do
});
What your want to achieve is not possible with only one query in Bookshelf. You probably need to do a first query using knex to get a list of Action ids and then give them to Bookshelf.js
db.bookshelf.knex.raw(`
select ActionAssignedTo.action_Id as actionId,
from Action
inner join Employee
on Action.created_By_Id = Employee.id
and Employee.vendor_Id = ?
inner join ActionAssignedTo
on Action.id = ActionAssignedTo.action_Id
and ActionAssignedTo.action_Id = ?
where Action.created_By_Id = ?
group by Action.id
limit ?`,
[2, 3, 7, 2]
)
.then(result => {
const rows = result.rows;
// Do what you have to do
})
And then use the recovered Ids to get your Bookshelf query like this
Model.Action
.query(qb => {
qb.whereIn('id', rows);
})
.fetchAll({
withRelated: [{
'createdBy': qb => {
qb.columns(['id', 'firstname', 'lastname']);
},
'assignedTo': qb => {
qb.columns(['action_Id', 'employee_Id']);
},
'assignedTo.employee': qb => {
qb.columns(['id', 'firstname', 'lastname']);
},
}],
columns: ['id', 'name', 'completed_At', 'deadline', 'notes']
})
.fetchAll(data => {
// Do what you have to do
});
Note that the columns used for joins MUST BE in the columns list for each table. If you omit the columns, all the columns will be selected.
By default, Bookshelf will retrieve all columns and all root objects. The default is kind of LEFT OUTER JOIN.

mysql search child & parent table fields with sequelize in nodejs

In my Node application we have used Sequelize to connect with mysql
Have two table User & UserOption
User table have following fields
user_id(pk)
user_email
UserOption table have following fields
option_id(pk)
user_id(fk)
first_name
I need to list all user by search text in user_email & first_name
Is there any option to search both parent & child table fields in Sequelize?
UPDATE
User table
user_id user_email
1 text#text.com
2 anything#anything.com
3 jhon#smthng.com
UserOption table
option_id user_id first_name
1 1 jhon
2 2 smith
3 3 david
If I search for "jhon", the result will be both user with id 1 and 2
You need to include model UserOption in lookup on model User. This generates a JOIN clause with condition UserOption.user_id = User.user_id, as well as adds specified WHERE clause to perform text lookup on user_email and first_name columns of both tables
User.findAll({
where: {
user_email: { $like: '%text%' }
},
include: [
{
model: UserOption,
where: {
first_name: { $like: '%text%' }
},
attributes: []
}
]
}).then((users) => {
// result
});
EDIT
Basing on your updated question, I think that you can try using sequelize.literal method, but, according to the documentation:
Creates a object representing a literal, i.e. something that will not be escaped.
So it is necessary to escape desired values by yourself
let escValue = sequelize.escape(lookupText);
User.findAll({
where: {
$or: [
{ email: { $like: '%' + lookupText + '%' },
{ id: { $in: sequelize.literal(`(SELECT uo.user_id FROM user_options uo WHERE uo.first_name LIKE CONCAT('%', ${escValue}, '%'))`) }
]
}
}).then((users) => {
// result...
});
It would generate a query which selects users from users table where email LIKE '%text%' or where users.id is in specified query result.
I am very curious if this satisfies your needs, waiting for feedback.

Yii2 order by 3rd table's value

I'm working with Yii2 and I can't solve it out. I need to OrderBy first table's rows by the third table's column.
First table: user [id, ....]
Second table: info [id, user_id, city_id, ...]
Third table: city [id, title, latitude, longitude]
models/User:
public function getInfo()
{
return $this->hasOne(InfoClear::className(), ['user_id' => 'id']);
}
models/Info
public function getCity()
{
return $this->hasOne(City::className(), ['id' => 'city_id']);
}
models/RecommendedSearch
$query = User::find()->joinWith(['info']);
Also I have to connect somehow 'city' table
Somthing like this
User::find()->joinWith(['info' => function(\yii\db\ActiveQuery $q){
$q->joinWith('city');
}]);
Or try
User::find()->with('info.city')->all();