Add multiple rows in Laravel DB Query (for migrating WordPress usermeta table into new Laravel table) - sql

I'm migrating Users from WordPress to Laravel. I want to join the users and user_meta tables. Then I will import into a new table.
In my user_meta table I have multiple rows assigned to the user_id. How do I import multiple rows with their own unique identifier.
Eg.
umeta_id = 1, user_id = 1, meta_key = first_name, meta_value = Bob
umeta_id = 2, user_id = 1, meta_key = last_name, meta_value = Builder
In the above example, I'd like to add first_name and last_name to the query output.
Then import into a new column in the Laravel DB (and stop using the user_meta reference table approach WordPress uses).
Here is my current query code and the output I get:
$wp_users = DB::connection('wordpress_db')
// ->select(DB::raw('um.meta_value as first_name'))
->select('um.meta_value as first_name')
->table('wp_users')
->leftJoin('wp_usermeta as um', function ($q) {
$q->on('um.user_id', '=', 'wp_users.id')
->where('um.meta_key', '=', "first_name");
})
->orderBy('wp_users.id');
and if i dump the output:
+"ID": 1
+"user_login": "123"
+"user_pass": "123"
+"user_nicename": "123"
+"user_email": "b#x"
+"user_url": "https://x"
+"user_registered": "2016-1-1 13:47:32"
+"user_activation_key": ""
+"user_status": 0
+"display_name": "Bobby Builds"
+"umeta_id": 222
+"user_id": 1
+"meta_key": "first_name"
+"meta_value": "Bob"
Rather than meta_value and meta_key I just want 'first_name' => 'bob' and then also the ability to do this for multiple values in the user_meta reference table
If I was writing RAW sql then I think I would approach this by having a left_join per value I want to get. I would then create an alias like
SELECT um1.meta_value as first_name
SELECT um2.meta_value as last_name
LEFTJOIN wp_usermeta as um1
LEFTJOIN wp_usermeta as um2
I've noodled around without luck - any ideas appreciated.
Thanks!
I've written about some of the processes involved here for further reference: http://raison.co/migrating-wordpress-users-to-laravel/

I did this in the end by using select to choose all columns from wp_users and then selectively adding the new joins.
See the code fixed code below:
$wp_users = DB::connection('wp_db')
->table('wp_users')
->leftJoin('wp_usermeta as um', function ($q) {
$q->on('um.user_id', '=', 'wp_users.id')
->where('um.meta_key', '=', "wbp_user_mob_phone");
})
->leftJoin('wp_usermeta as um2', function ($q) {
$q->on('um2.user_id', '=', 'wp_users.id')
->where('um2.meta_key', '=', "first_name");
})
->select('wp_users.*', 'um.meta_value as wbp_user_mob_phone', 'um2.meta_value as first_name')
->orderBy('wp_users.id');

Related

SQL Postgre to show 1 data if get same some multiple data and how to implement to laravel query

i want to ask about sql in postgresql, i got data from join with 3 table, i got the result but i got multiple data like this image
result
and here my sql code in postgresql
select users.* from users inner join model_has_roles on model_has_roles.model_id = users.id
left join roles on roles.id = model_has_roles.role_id where roles.name not in ('job-seeker') order by users.name asc
how to fix this query where i got the multiple data only 1 data to show.
and i want this sql to implement to laravel query and here my code now
public function getAccountList(){
$req = app(Request::class);
// $getAccount = User::query();
$getAccount = User::join('model_has_roles', function($join) {
$join->on('users.id', '=', 'model_has_roles.model_id');
})->leftJoin('roles', function($join){
$join->on('model_has_roles.role_id', '=', 'roles.id');
});
$getAccount->whereNotIn('roles.name', ['job-seeker']);
if ($q = $req->query('q')) {
$searchTerm = trim(strtolower($q));
$getAccount->whereRaw(
'LOWER(users.name) like (?) or LOWER(users.email) like (?)',
["%{$searchTerm}%", "%{$searchTerm}%"]
);
}
// $getAccount->get()->unique('name');
$getAccount->select(['users.*']);
$paginator = $this->pagination($getAccount);
return $this->paginate($paginator, new UserTransformer);
}
how to fix the query only 1 data to show not the multiple same data. thank you for helping me. God Bless You
use distinct()
$data = DB::table('test')->[your query builder]->distinct()->get();
Laravel Query Builder Docs
Just change a bit to make it related to your query builder

I need to get Subject name with total number of Book

I have a SQL Query which I want to convert in Linq or want to show data
as pictured here
Here is the query:
select sae_subcategorymaster.subject, count(sae_tblbookdetail.title)
from sae_tblbookdetail inner join sae_subcategorymaster
on sae_subcategorymaster.subject=sae_tblbookdetail.subject
group by sae_subcategorymaster.subject
What is a simple way to do this?
Grouping is supported in LinqEF. Provided you have your entities related. (Books have a reference to their subcategory.)
var totals = context.Books
.GroupBy(book => book.SubCategory.Subject)
.Select(group => new
{
Subject = group.Key,
BookCount = group.Count()
}).ToList();

Mongoose and sql comparison

This is a multi question
From a mongoose result I have several items in the result which I get through result.length.
How can I get specific items e.g.
Person.find({'exployment.office':'Greenway'})
.exec(function(err, result){
//from the result, how can i get those items with
result.length would give me the number of items in the result
but how can i get a specific item without having to use loop to get
the specific item within the result
//There are like fifty people in the result,
//how can i get the number of items in result
});
In SQL, I have a query like this
select *
from table1, table2
where table2.field2 = value1
and table2.field2 = table1.field2
and table1.value1 = value3
e.g.
select *
from city, state
where state.name = 'xxy'
and state.id = city.state_id
and city.name != 'yyy'
How can this be converted to mongoose?
In SQL if I want to select people whose first name are e.g. Smith, Queen I can use things like
select *
from table
where first_name in (Smith, Queen)
This would give me result for people whose first_name matches SMith and Queen
How can I do this in mongoose?
select *
from Person
where first_name in (Smith, Queen)
Would simply be this using $in:
Person.find({'first_name': { $in: ['Smith', 'Queen']}}) ...
Next one:
select *
from city, state
where state.name = 'xxy'
and state.id = city.state_id
and city.name != 'yyy'
Using mongoose, you would need to use populate and create the schemas with ref relationships.
City.find({ "name": { $ne: "yyy"} }).populate({
"path": "state",
"match": { "state.name": "xxy" }
}) ...
Next one:
Person.find({'exployment.office':'Greenway'})
.exec(function(err, result){
//from the result, how can i get those items with
result.length would give me the number of items in the result
but how can i get a specific item without having to use loop to get
the specific item within the result
//There are like fifty people in the result,
//how can i get the number of items in result
});
You would filter as much as you can before you exec the query to get the records you need rather than filter after you get all in the result. result.length sure would give you the count although you could get the count via something like this;
Person.count({first_name: "Smith"}).exec() ...

Rails SQL in controller

I'm using Xeditable and RABL in a Rails app.
I have a workorder that belongs to a workgroup.
I want to assign the workorder to an employee in that workgroup.
I'm using this as the source in the Xeditable:
data-source="/employees.json?workgroup=<%= workorder.workgroup.id%>"
And this is the code I'm trying in the employee controller:
def index
#employees = Employee.order(:first_name)
#employees = Employee.joins(:empgroups).where(:workgroup_id => params[:workgroup]) if params[:workgroup].present?
end
This is the SQL that gets generated:
SELECT "employees".* FROM "employees" INNER JOIN "empgroups" ON "empgroups"."employee_id" = "employees"."id" WHERE "employees"."workgroup_id" = 2
The issue is the WHERE should be `WHERE "empgroups"."workgroup_id" = 2
How do I change this line of code?
#employees = Employee.joins(:empgroups).where(:workgroup_id => params[:workgroup]) if params[:workgroup].present?
Thanks for the help!
You can use nested hash syntax:
#employees = Employee.joins(:empgroups).where(
empgroups: { workgroup_id: params[:workgroup] }
) if params[:workgroup].present?
This should work:
Employee.joins(:empgroups).where(:empgroups => {:workgroup_id => params[:workgroup]})
The :workgroup_id is actually an attribute/column on a joined table, and not on the base table that you are querying from, so you need to specify where that column is located during the where clause.
Remember that in a pinch you can also type in SQL for the where clause, but will also have to remember to properly reference the right table.
Employee.joins(:empgroups).where("empgroups.workgroup_id = ?", params[:workgroup])

Rails ActiveRecord Join Query With conditions

I have following SQL Query:
SELECT campaigns.* , campaign_countries.points, offers.image
FROM campaigns
JOIN campaign_countries ON campaigns.id = campaign_countries.campaign_id
JOIN countries ON campaign_countries.country_id = countries.id
JOIN offers ON campaigns.offer_id = offers.id
WHERE countries.code = 'US'
This works perfectly well. I want its rails active record version some thing like:
Campaign.includes(campaign_countries: :country).where(countries: {code: "US"})
Above code runs more or less correct query (did not try to include offers table), issue is returned result is collection of Campaign objects so obviously it does not include Points
My tables are:
campaigns --HAS_MANY--< campaign_countries --BELONGS_TO--< countries
campaigns --BELONGS_TO--> offers
Any suggestions to write AR version of this SQL? I don't want to use SQL statement in my code.
I some how got this working without SQL but surely its poor man's solution:
in my controller I have:
campaigns = Campaign.includes(campaign_countries: :country).where(countries: {code: country.to_s})
render :json => campaigns.to_json(:country => country)
in campaign model:
def points_for_country country
CampaignCountry.joins(:campaign, :country).where(countries: {code: country}, campaigns: {id: self.id}).first
end
def as_json options={}
json = {
id: id,
cid: cid,
name: name,
offer: offer,
points_details: options[:country] ? points_for_country(options[:country]) : ""
}
end
and in campaign_countries model:
def as_json options={}
json = {
face_value: face_value,
actual_value: actual_value,
points: points
}
end
Why this is not good solution? because it invokes too many queries:
1. It invokes query when first join is performed to get list of campaigns specific to country
2. For each campaign found in first query it will invoke one more query on campaign_countries table to get Points for that campaign and country.
This is bad, Bad and BAD solution. Any suggestions to improve this?
If You have campaign, You can use campaign.campaign_countries to get associated campaign_countries and just get points from them.
> campaign.campaign_countries.map(&:points)
=> [1,2,3,4,5]
Similarly You will be able to get image from offers relation.
EDIT:
Ok, I guess now I know what's going on. You can use joins with select to get object with attached fields from join tables.
cs = Campaign.joins(campaign_countries: :country).joins(:offers).select('campaigns.*, campaign_countries.points, offers.image').where(countries: {code: "US"})
You can than reference additional fields by their name on Campaign object
cs.first.points
cs.first.image
But be sure, that additional column names do not overlap with some primary table fields or object methods.
EDIT 2:
After some more research I came to conclusion that my first version was actually correct for this case. I will use my own console as example.
> u = User.includes(:orders => :cart).where(:carts => { :id => [5168, 5167] }).first
> u.orders.length # no query is performed
=> 2
> u.orders.count # count query is performed
=> 5
So when You use includes with condition on country, in campaign_countries are stored only campaign_countries that fulfill Your condition.
Try this:
Campaign.joins( [{ :campaign_countries => :countries}, :offers]).where('`countries`.`code` = ?', "US")