Laravel-How 当一列在两个 collection 中通用时合并两个 collection?
Laravel-How to merge two collections when one column is common in both collection?
我正在使用 Laravel 5.6.38。
我有两个collections。
Collection 1
[{
"link": "http://example.com/posts/1",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 1",
"post_id": 1,
"priority": "2",
"identifiedBy": "x",
},
{
"link": "http://example.com/posts/2",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 2",
"post_id": 2,
"priority": "3",
"identifiedBy": "x",
}]
Collection 2
[{
"post_id": 1,
"qatagger": "Mr. X"
}]
预期结果
[{
"link": "http://example.com/posts/1",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 1",
"post_id": 1,
"priority": "2",
"identifiedBy": "x",
"qatagger": "Mr. X"
},
{
"link": "http://example.com/posts/2",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 2",
"post_id": 2,
"priority": "3",
"identifiedBy": "x",
}]
我尝试了 $collection1->merge($collection2),得到了结果
[{
"link": "http://example.com/posts/1",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 1",
"post_id": 1,
"priority": "2",
"identifiedBy": "superadmin"
},
{
"link": "http://example.com/posts/2",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 2",
"post_id": 2,
"priority": "3",
"identifiedBy": "superadmin"
},
{
"post_id": 1,
"qatagger": "Mr. x"
}]
有没有不用任何循环就能得到预期结果的方法?
更新
第一次加入
$posts = DB::table('posts')
->where('posts.post_status_id', '=', $status)
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments
GROUP BY comment_type, post_id ASC) AND comment_type = 'vip_comment') comments_vip"), 'posts.post_id', '=', 'comments_vip.post_id')
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments
GROUP BY comment_type, post_id ASC) AND comment_type = 'pm_comment') comments_pm"), 'posts.post_id', '=', 'comments_pm.post_id')
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments GROUP BY comment_type, post_id ASC) AND comment_type = 'bagging_qa_comment') comments_bq"),'posts.post_id', '=', 'comments_bq.post_id')
->leftJoin('users AS identifiedByUser', function($join) {
$join->on('posts.post_identified_by', '=', 'identifiedByUser.id');
})
->select(['posts.post_id as post_id', 'posts.post_link as link', 'posts.post_status_id as status_id', 'posts.post_description as description', 'posts.post_priority as priority', 'posts.created_at as created_at', 'comments_vip.comment AS vip_comment', 'comments_pm.comment AS
pm_comment', 'comments_bq.comment as bagger_qa_comment', 'identifiedByUser.name as identifiedBy'])
->groupBy('post_id')
->get();
第二次加入
$baggers = DB::table('post_baggings')
->leftJoin('posts', 'post_baggings.post_id', '=', 'posts.post_id' )
->join('users AS baggers', function($join) {
$join->on('post_baggings.bagging_team_id', '=', 'baggers.id');
})->select(array('posts.post_id as post_id', 'baggers.name as bagger'))
->get()->keyBy('post_id');
正在合并
$out = [];
foreach ($posts as $key => $post){
$post->priority = Priority::where('priority_id', '=', $post->priority)->pluck('display_name')->first();
$post = new Collection($post);
$out[] = $post->merge($baggers[$post['post_id']]);
}
结果退出后不能合并,必须在查询中合并,
在任何基础上,您将被纳入此结果,此处没有要求。
这个解决方案,但我不认为是真的
$arr1 = json_decode('[{
"link": "http://example.com/posts/1",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 1",
"post_id": 1,
"priority": "2",
"identifiedBy": "x"
},
{
"link": "http://example.com/posts/2",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 2",
"post_id": 2,
"priority": "3",
"identifiedBy": "x"
}]');
$arr2 = json_decode('[{
"post_id": 1,
"qatagger": "Mr. X"
}]');
$arr1[0] = (object)array_merge((array)$arr1[0],(array)$arr2[0]);
dd(new \Illuminate\Support\Collection($arr1));
解决方法是
$out = array();
foreach ($collections1 as $key => $collection1){
$out[] = (object)array_merge((array)$collections2[$key], (array)$value);
}
dd(new \Illuminate\Support\Collection($out));
更好的方法(目前可行的解决方案)可以是
$out = [];
foreach ($posts as $key => $post){
$post->priority = Priority::where('priority_id', '=', $post->priority)->pluck('display_name')->first();
$post = new Collection($post);
$out[] = $post->merge($taggers[$post['post_id']]);
}
return new Collection($out);
再次解决方法。
正如我在评论中所建议的那样,您可以将 table 添加为查询中的额外连接,以从数据库中获取结果。像下面这样的东西可能会起作用:
$posts = DB::table('posts')
->where('posts.post_status_id', '=', $status)
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments
GROUP BY comment_type, post_id ASC) AND comment_type = 'vip_comment') comments_vip"), 'posts.post_id', '=', 'comments_vip.post_id')
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments
GROUP BY comment_type, post_id ASC) AND comment_type = 'pm_comment') comments_pm"), 'posts.post_id', '=', 'comments_pm.post_id')
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments GROUP BY comment_type, post_id ASC) AND comment_type = 'bagging_qa_comment') comments_bq"),'posts.post_id', '=', 'comments_bq.post_id')
->leftJoin('users AS identifiedByUser', function($join) {
$join->on('posts.post_identified_by', '=', 'identifiedByUser.id');
})
->select(['posts.post_id as post_id', 'posts.post_link as link', 'posts.post_status_id as status_id', 'posts.post_description as description', 'posts.post_priority as priority', 'posts.created_at as created_at', 'comments_vip.comment AS vip_comment', 'comments_pm.comment AS
pm_comment', 'comments_bq.comment as bagger_qa_comment', 'identifiedByUser.name as identifiedBy', 'joinedTable.bagger as bagger'])
->leftJoin(DB::raw('('.
DB::table('post_baggings')
->leftJoin('posts', 'post_baggings.post_id', '=', 'posts.post_id' )
->join('users AS baggers', function($join) {
$join->on('post_baggings.bagging_team_id', '=', 'baggers.id');
})->select(array('posts.post_id as post_id', 'baggers.name as bagger'))->toSql()
.') as joinedTable'), 'joinedTable.post_id', 'posts.post_id')
->groupBy('post_id')
->get();
这是利用方法 toSql
的优势,它将保留您为第二个案例所做的确切查询。不过我还没有实际测试过。
使用生成的集合的解决方法是:
$result1->map(function ($row) use ($result2) {
if ($result2->has($row->post_id)) {
return collect(array_merge((array)$row, (array)$result2)); //Casting to arrays and then to a collection.
}
return collect((array)$row);
});
我正在使用 Laravel 5.6.38。
我有两个collections。
Collection 1
[{
"link": "http://example.com/posts/1",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 1",
"post_id": 1,
"priority": "2",
"identifiedBy": "x",
},
{
"link": "http://example.com/posts/2",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 2",
"post_id": 2,
"priority": "3",
"identifiedBy": "x",
}]
Collection 2
[{
"post_id": 1,
"qatagger": "Mr. X"
}]
预期结果
[{
"link": "http://example.com/posts/1",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 1",
"post_id": 1,
"priority": "2",
"identifiedBy": "x",
"qatagger": "Mr. X"
},
{
"link": "http://example.com/posts/2",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 2",
"post_id": 2,
"priority": "3",
"identifiedBy": "x",
}]
我尝试了 $collection1->merge($collection2),得到了结果
[{
"link": "http://example.com/posts/1",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 1",
"post_id": 1,
"priority": "2",
"identifiedBy": "superadmin"
},
{
"link": "http://example.com/posts/2",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 2",
"post_id": 2,
"priority": "3",
"identifiedBy": "superadmin"
},
{
"post_id": 1,
"qatagger": "Mr. x"
}]
有没有不用任何循环就能得到预期结果的方法?
更新 第一次加入
$posts = DB::table('posts')
->where('posts.post_status_id', '=', $status)
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments
GROUP BY comment_type, post_id ASC) AND comment_type = 'vip_comment') comments_vip"), 'posts.post_id', '=', 'comments_vip.post_id')
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments
GROUP BY comment_type, post_id ASC) AND comment_type = 'pm_comment') comments_pm"), 'posts.post_id', '=', 'comments_pm.post_id')
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments GROUP BY comment_type, post_id ASC) AND comment_type = 'bagging_qa_comment') comments_bq"),'posts.post_id', '=', 'comments_bq.post_id')
->leftJoin('users AS identifiedByUser', function($join) {
$join->on('posts.post_identified_by', '=', 'identifiedByUser.id');
})
->select(['posts.post_id as post_id', 'posts.post_link as link', 'posts.post_status_id as status_id', 'posts.post_description as description', 'posts.post_priority as priority', 'posts.created_at as created_at', 'comments_vip.comment AS vip_comment', 'comments_pm.comment AS
pm_comment', 'comments_bq.comment as bagger_qa_comment', 'identifiedByUser.name as identifiedBy'])
->groupBy('post_id')
->get();
第二次加入
$baggers = DB::table('post_baggings')
->leftJoin('posts', 'post_baggings.post_id', '=', 'posts.post_id' )
->join('users AS baggers', function($join) {
$join->on('post_baggings.bagging_team_id', '=', 'baggers.id');
})->select(array('posts.post_id as post_id', 'baggers.name as bagger'))
->get()->keyBy('post_id');
正在合并
$out = [];
foreach ($posts as $key => $post){
$post->priority = Priority::where('priority_id', '=', $post->priority)->pluck('display_name')->first();
$post = new Collection($post);
$out[] = $post->merge($baggers[$post['post_id']]);
}
结果退出后不能合并,必须在查询中合并, 在任何基础上,您将被纳入此结果,此处没有要求。
这个解决方案,但我不认为是真的
$arr1 = json_decode('[{
"link": "http://example.com/posts/1",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 1",
"post_id": 1,
"priority": "2",
"identifiedBy": "x"
},
{
"link": "http://example.com/posts/2",
"created_at": "2018-09-20 05:14:10",
"description": "some desc 2",
"post_id": 2,
"priority": "3",
"identifiedBy": "x"
}]');
$arr2 = json_decode('[{
"post_id": 1,
"qatagger": "Mr. X"
}]');
$arr1[0] = (object)array_merge((array)$arr1[0],(array)$arr2[0]);
dd(new \Illuminate\Support\Collection($arr1));
解决方法是
$out = array();
foreach ($collections1 as $key => $collection1){
$out[] = (object)array_merge((array)$collections2[$key], (array)$value);
}
dd(new \Illuminate\Support\Collection($out));
更好的方法(目前可行的解决方案)可以是
$out = [];
foreach ($posts as $key => $post){
$post->priority = Priority::where('priority_id', '=', $post->priority)->pluck('display_name')->first();
$post = new Collection($post);
$out[] = $post->merge($taggers[$post['post_id']]);
}
return new Collection($out);
再次解决方法。
正如我在评论中所建议的那样,您可以将 table 添加为查询中的额外连接,以从数据库中获取结果。像下面这样的东西可能会起作用:
$posts = DB::table('posts')
->where('posts.post_status_id', '=', $status)
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments
GROUP BY comment_type, post_id ASC) AND comment_type = 'vip_comment') comments_vip"), 'posts.post_id', '=', 'comments_vip.post_id')
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments
GROUP BY comment_type, post_id ASC) AND comment_type = 'pm_comment') comments_pm"), 'posts.post_id', '=', 'comments_pm.post_id')
->leftJoin(DB::raw("(SELECT post_id, comment, comment_type FROM comments WHERE comment_id in (SELECT MAX(comment_id) FROM comments GROUP BY comment_type, post_id ASC) AND comment_type = 'bagging_qa_comment') comments_bq"),'posts.post_id', '=', 'comments_bq.post_id')
->leftJoin('users AS identifiedByUser', function($join) {
$join->on('posts.post_identified_by', '=', 'identifiedByUser.id');
})
->select(['posts.post_id as post_id', 'posts.post_link as link', 'posts.post_status_id as status_id', 'posts.post_description as description', 'posts.post_priority as priority', 'posts.created_at as created_at', 'comments_vip.comment AS vip_comment', 'comments_pm.comment AS
pm_comment', 'comments_bq.comment as bagger_qa_comment', 'identifiedByUser.name as identifiedBy', 'joinedTable.bagger as bagger'])
->leftJoin(DB::raw('('.
DB::table('post_baggings')
->leftJoin('posts', 'post_baggings.post_id', '=', 'posts.post_id' )
->join('users AS baggers', function($join) {
$join->on('post_baggings.bagging_team_id', '=', 'baggers.id');
})->select(array('posts.post_id as post_id', 'baggers.name as bagger'))->toSql()
.') as joinedTable'), 'joinedTable.post_id', 'posts.post_id')
->groupBy('post_id')
->get();
这是利用方法 toSql
的优势,它将保留您为第二个案例所做的确切查询。不过我还没有实际测试过。
使用生成的集合的解决方法是:
$result1->map(function ($row) use ($result2) {
if ($result2->has($row->post_id)) {
return collect(array_merge((array)$row, (array)$result2)); //Casting to arrays and then to a collection.
}
return collect((array)$row);
});