質問編集履歴

8

バージョン情報の詳細を記述

2020/11/12 09:24

投稿

gyu
gyu

スコア3

test CHANGED
File without changes
test CHANGED
@@ -100,7 +100,9 @@
100
100
 
101
101
  ## 環境
102
102
 
103
- Laravel6
103
+ Laravel6.0
104
+
105
+ (laravel6.6にアップグレードしても改善なし)
104
106
 
105
107
 
106
108
 

7

背景を修正

2020/11/12 09:24

投稿

gyu
gyu

スコア3

test CHANGED
File without changes
test CHANGED
@@ -284,6 +284,8 @@
284
284
 
285
285
 
286
286
 
287
+ ### getだとエラーなし
288
+
287
289
  ```
288
290
 
289
291
  $query = DB::table('posts')
@@ -310,14 +312,50 @@
310
312
 
311
313
 
312
314
 
315
+ $posts = $query->orderBy('posts.created_at', 'desc')->get();
316
+
317
+ ```
318
+
319
+
320
+
321
+ `get()`で取得する分にはエラーなしで実行できます。
322
+
323
+
324
+
325
+ ### paginateだとエラー
326
+
327
+ ```
328
+
329
+ $query = DB::table('posts')
330
+
331
+ ->join('likes', 'posts.id', '=', 'likes.post_id')
332
+
333
+ ->select('*', 'count(likes.id) AS likes_count')
334
+
335
+ ->groupBy('posts.id');
336
+
337
+
338
+
339
+ if ($lgtm_min !== null) {
340
+
341
+ $query->having('likes_count', '>=', $lgtm_min);
342
+
343
+ }
344
+
345
+ if ($lgtm_max !== null) {
346
+
347
+ $query->having('likes_count', '<=', $lgtm_max);
348
+
349
+ }
350
+
351
+
352
+
313
353
  $posts = $query->orderBy('posts.created_at', 'desc')->paginate(20);
314
354
 
315
355
  ```
316
356
 
317
357
 
318
358
 
319
- しかし、
320
-
321
359
 
322
360
 
323
361
  エラー
@@ -330,6 +368,10 @@
330
368
 
331
369
 
332
370
 
371
+
372
+
373
+
374
+
333
375
  調べてみると、
334
376
 
335
377
  `withCount()`は、`having()`と`->paginate()`と併用して利用できないことが判明しました。
@@ -476,100 +518,6 @@
476
518
 
477
519
 
478
520
 
479
- // period search
480
-
481
- if ($period !== null) {
482
-
483
- switch ($period) {
484
-
485
- case "day":
486
-
487
- $query->where([
488
-
489
- ['posts.created_at', '>=', date("Y-m-d 00:00:00")],
490
-
491
- ['posts.created_at', '<=', date("Y-m-d 23:59:59")]
492
-
493
- ]);
494
-
495
- case "week":
496
-
497
- $query->where([
498
-
499
- ['posts.created_at', '>=', date("Y-m-d 00:00:00", strtotime("-1 week"))],
500
-
501
- ['posts.created_at', '<=', date("Y-m-d 23:59:59")]
502
-
503
- ]);
504
-
505
- case "month":
506
-
507
- $query->where([
508
-
509
- ['posts.created_at', '>=', date("Y-m-d 00:00:00", strtotime("-1 month"))],
510
-
511
- ['posts.created_at', '<=', date("Y-m-d 23:59:59")]
512
-
513
- ]);
514
-
515
- case "period":
516
-
517
- $query->where([
518
-
519
- ['posts.created_at', '>=', date("{$period_start} 00:00:00")],
520
-
521
- ['posts.created_at', '<=', date("{$period_end} 23:59:59")]
522
-
523
- ]);
524
-
525
- }
526
-
527
- }
528
-
529
-
530
-
531
- if ($keyword !== null) {
532
-
533
- // tags search
534
-
535
- if (count($tags) !== 0) {
536
-
537
- $query
538
-
539
- ->join('post_tags', 'posts.id', '=', 'post_tags.post_id')
540
-
541
- ->join('tags', 'post_tags.tag_id', '=', 'tags.id')
542
-
543
- ->whereIn('tags.name', $tags)
544
-
545
- ->groupBy('posts.id')
546
-
547
- ->havingRaw('count(distinct tags.id) = ?', [count($tags)]);
548
-
549
- }
550
-
551
-
552
-
553
- // keywords search
554
-
555
- foreach ($no_tag_keywords as $no_tag_keyword) {
556
-
557
- $query
558
-
559
- ->where(function ($query) use ($no_tag_keyword) {
560
-
561
- $query
562
-
563
- ->where('posts.title', 'like', '%' . $no_tag_keyword . '%')
564
-
565
- ->orWhere('posts.body', 'LIKE', "%{$no_tag_keyword}%");
566
-
567
- });
568
-
569
- }
570
-
571
- }
572
-
573
521
 
574
522
 
575
523
 

6

モデルを追加

2020/11/12 09:22

投稿

gyu
gyu

スコア3

test CHANGED
File without changes
test CHANGED
@@ -106,10 +106,130 @@
106
106
 
107
107
  ## モデル
108
108
 
109
+ ### postモデル
110
+
109
111
 
110
112
 
111
113
  ```post
112
114
 
115
+ <?php
116
+
117
+
118
+
119
+ namespace App\Models;
120
+
121
+
122
+
123
+ use Illuminate\Database\Eloquent\Model;
124
+
125
+
126
+
127
+ class post extends Model
128
+
129
+ {
130
+
131
+ protected $fillable = [
132
+
133
+ 'title', 'body', 'user_id'
134
+
135
+ ];
136
+
137
+
138
+
139
+ public function user()
140
+
141
+ {
142
+
143
+ return $this->belongsTo('App\User');
144
+
145
+ }
146
+
147
+ public function tags()
148
+
149
+ {
150
+
151
+ return $this->belongsToMany('App\Models\tag', 'post_tags');
152
+
153
+ }
154
+
155
+
156
+
157
+ public function likes()
158
+
159
+ {
160
+
161
+ return $this->hasMany('App\Models\like');
162
+
163
+ }
164
+
165
+ }
166
+
167
+
168
+
169
+ ```
170
+
171
+
172
+
173
+ ### likeモデル
174
+
175
+ ```like
176
+
177
+ <?php
178
+
179
+
180
+
181
+ namespace App\Models;
182
+
183
+
184
+
185
+ use Illuminate\Database\Eloquent\Model;
186
+
187
+
188
+
189
+ class like extends Model
190
+
191
+ {
192
+
193
+ protected $fillable = [
194
+
195
+ 'user_id', 'post_id'
196
+
197
+ ];
198
+
199
+
200
+
201
+ public function post()
202
+
203
+ {
204
+
205
+ return $this->belongsTo('App\Models\post');
206
+
207
+ }
208
+
209
+
210
+
211
+ public function user()
212
+
213
+ {
214
+
215
+ return $this->belongsTo('App\User');
216
+
217
+ }
218
+
219
+ }
220
+
221
+
222
+
223
+ ```
224
+
225
+
226
+
227
+ ## マイグレーション
228
+
229
+
230
+
231
+ ```post
232
+
113
233
  Schema::create('posts', function (Blueprint $table) {
114
234
 
115
235
  $table->bigIncrements('id');

5

コメントアウトを追加

2020/11/12 08:59

投稿

gyu
gyu

スコア3

test CHANGED
File without changes
test CHANGED
@@ -458,10 +458,14 @@
458
458
 
459
459
  if ($order == 'new') {
460
460
 
461
+ //paginate()だとエラーあり。こちらもget()にすればエラーなし
462
+
461
463
  $posts = $query->orderBy('posts.created_at', 'desc')->paginate(20);
462
464
 
463
465
  } else {
464
466
 
467
+ //get()だとエラーなし。こちらもpaginate()にすればエラーあり
468
+
465
469
  $posts = $query->orderBy('likes_count', 'desc')->get();
466
470
 
467
471
  }

4

抜粋なしのコードを追加

2020/11/12 08:42

投稿

gyu
gyu

スコア3

test CHANGED
File without changes
test CHANGED
@@ -274,4 +274,206 @@
274
274
 
275
275
 
276
276
 
277
+ ## 抜粋なしのコード
278
+
279
+ 要望があったので、記述します。
280
+
281
+
282
+
283
+ ```index
284
+
285
+ $query = Post::withCount('likes');
286
+
287
+ $posts = DetailedSearch::DetailedSearch($query, $keyword, $request);
288
+
289
+ return view('posts.index', compact('posts', 'all_posts_count', 'keyword'));
290
+
291
+ ```
292
+
293
+
294
+
295
+ ```DetailedSearch
296
+
297
+ <?php
298
+
299
+
300
+
301
+ namespace App\Services;
302
+
303
+
304
+
305
+ class DetailedSearch
306
+
307
+ {
308
+
309
+ public static function DetailedSearch($query, $keyword, $request)
310
+
311
+ {
312
+
313
+ // values
314
+
315
+ $order = $request->input('order');
316
+
317
+ $lgtm_min = $request->input('lgtm-min');
318
+
319
+ $lgtm_max = $request->input('lgtm-max');
320
+
321
+ $period = $request->input('period');
322
+
323
+ $period_start = $request->input('period-start');
324
+
325
+ $period_end = $request->input('period-end');
326
+
327
+
328
+
329
+ //keyword
330
+
331
+ $keyword_space_half = mb_convert_kana($keyword, 's');
332
+
333
+ $keywords = preg_split('/[\s]+/', $keyword_space_half);
334
+
335
+ preg_match_all('/#([a-zA-z0-90-9ぁ-んァ-ヶ亜-熙]+)/u', $keyword, $match);
336
+
337
+ $no_tag_keywords = array_diff($keywords, $match[0]);
338
+
339
+ $tags = $match[1];
340
+
341
+
342
+
343
+ //LGTM sum search
344
+
345
+ if ($lgtm_min !== null) {
346
+
347
+ $query->having('likes_count', '>=', $lgtm_min);
348
+
349
+ }
350
+
351
+ if ($lgtm_max !== null) {
352
+
353
+ $query->having('likes_count', '<=', $lgtm_max);
354
+
355
+ }
356
+
357
+
358
+
359
+ // period search
360
+
361
+ if ($period !== null) {
362
+
363
+ switch ($period) {
364
+
365
+ case "day":
366
+
367
+ $query->where([
368
+
369
+ ['posts.created_at', '>=', date("Y-m-d 00:00:00")],
370
+
371
+ ['posts.created_at', '<=', date("Y-m-d 23:59:59")]
372
+
373
+ ]);
374
+
375
+ case "week":
376
+
377
+ $query->where([
378
+
379
+ ['posts.created_at', '>=', date("Y-m-d 00:00:00", strtotime("-1 week"))],
380
+
381
+ ['posts.created_at', '<=', date("Y-m-d 23:59:59")]
382
+
383
+ ]);
384
+
385
+ case "month":
386
+
387
+ $query->where([
388
+
389
+ ['posts.created_at', '>=', date("Y-m-d 00:00:00", strtotime("-1 month"))],
390
+
391
+ ['posts.created_at', '<=', date("Y-m-d 23:59:59")]
392
+
393
+ ]);
394
+
395
+ case "period":
396
+
397
+ $query->where([
398
+
399
+ ['posts.created_at', '>=', date("{$period_start} 00:00:00")],
400
+
401
+ ['posts.created_at', '<=', date("{$period_end} 23:59:59")]
402
+
403
+ ]);
404
+
405
+ }
406
+
407
+ }
408
+
409
+
410
+
411
+ if ($keyword !== null) {
412
+
413
+ // tags search
414
+
415
+ if (count($tags) !== 0) {
416
+
417
+ $query
418
+
419
+ ->join('post_tags', 'posts.id', '=', 'post_tags.post_id')
420
+
421
+ ->join('tags', 'post_tags.tag_id', '=', 'tags.id')
422
+
423
+ ->whereIn('tags.name', $tags)
424
+
425
+ ->groupBy('posts.id')
426
+
427
+ ->havingRaw('count(distinct tags.id) = ?', [count($tags)]);
428
+
429
+ }
430
+
431
+
432
+
433
+ // keywords search
434
+
435
+ foreach ($no_tag_keywords as $no_tag_keyword) {
436
+
437
+ $query
438
+
439
+ ->where(function ($query) use ($no_tag_keyword) {
440
+
441
+ $query
442
+
443
+ ->where('posts.title', 'like', '%' . $no_tag_keyword . '%')
444
+
445
+ ->orWhere('posts.body', 'LIKE', "%{$no_tag_keyword}%");
446
+
447
+ });
448
+
449
+ }
450
+
451
+ }
452
+
453
+
454
+
455
+
456
+
457
+ // search order
458
+
459
+ if ($order == 'new') {
460
+
461
+ $posts = $query->orderBy('posts.created_at', 'desc')->paginate(20);
462
+
463
+ } else {
464
+
465
+ $posts = $query->orderBy('likes_count', 'desc')->get();
466
+
467
+ }
468
+
469
+ return $posts;
470
+
471
+ }
472
+
473
+ }
474
+
475
+ ```
476
+
477
+
478
+
277
479
  ご教授のほどよろしくお願い致します。

3

エラー文を追加

2020/11/12 08:41

投稿

gyu
gyu

スコア3

test CHANGED
File without changes
test CHANGED
@@ -200,6 +200,18 @@
200
200
 
201
201
 
202
202
 
203
+ エラー
204
+
205
+ ```
206
+
207
+ SQLSTATE[42S22]: Column not found: 1054 Unknown column 'likes_count' in 'having clause' (SQL: select count(*) as aggregate from `posts` where (`posts`.`title` like %100% or `posts`.`body` LIKE %100%) having `likes_count` >= 1)
208
+
209
+ ```
210
+
211
+
212
+
213
+ 調べてみると、
214
+
203
215
  `withCount()`は、`having()`と`->paginate()`と併用して利用できないことが判明しました。
204
216
 
205
217
 

2

`having()`を追加

2020/11/12 08:38

投稿

gyu
gyu

スコア3

test CHANGED
File without changes
test CHANGED
@@ -200,7 +200,7 @@
200
200
 
201
201
 
202
202
 
203
- `withCount()`は、`->paginate()`と併用して利用できないことが判明しました。
203
+ `withCount()`は、`having()`と`->paginate()`と併用して利用できないことが判明しました。
204
204
 
205
205
 
206
206
 

1

詳細を記述

2020/11/12 08:24

投稿

gyu
gyu

スコア3

test CHANGED
File without changes
test CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
 
5
- 下記のSQL文をクエリビルダに変換し、投稿(posts)のいいね(likes)の総数を取得したい。
5
+ 下記のSQL文をクエリビルダに変換し、投稿(posts)のいいね(likes)の総数を取得したい。
6
6
 
7
7
 
8
8
 
@@ -166,6 +166,74 @@
166
166
 
167
167
  ```
168
168
 
169
+ $query = DB::table('posts')
170
+
171
+ ->join('likes', 'posts.id', '=', 'likes.post_id')
172
+
173
+ ->select('*', 'count(likes.id) AS likes_count')
174
+
175
+ ->groupBy('posts.id');
176
+
177
+
178
+
179
+ if ($lgtm_min !== null) {
180
+
181
+ $query->having('likes_count', '>=', $lgtm_min);
182
+
183
+ }
184
+
185
+ if ($lgtm_max !== null) {
186
+
187
+ $query->having('likes_count', '<=', $lgtm_max);
188
+
189
+ }
190
+
191
+
192
+
193
+ $posts = $query->orderBy('posts.created_at', 'desc')->paginate(20);
194
+
195
+ ```
196
+
197
+
198
+
199
+ しかし、
200
+
201
+
202
+
203
+ `withCount()`は、`->paginate()`と併用して利用できないことが判明しました。
204
+
205
+
206
+
207
+ [【Laravelのissue】withCount(), having() and paginate() together not working](https://github.com/laravel/framework/issues/28476)
208
+
209
+
210
+
211
+ そのため、`withCount()`を利用せずに`likes_count`を定義する必要が出てきました。
212
+
213
+
214
+
215
+ そして、下記のSQL文をクエリビルダに変換しようと考えています
216
+
217
+
218
+
219
+ ```SQL
220
+
221
+ SELECT *,count(likes.id) AS likes_count
222
+
223
+ FROM posts
224
+
225
+ JOIN likes
226
+
227
+ on posts.id = likes.post_id
228
+
229
+ GROUP BY posts.id
230
+
231
+ ```
232
+
233
+
234
+
235
+ ```
236
+
169
237
  $query = Post::withCount('likes');
170
238
 
171
239
 
@@ -190,42 +258,6 @@
190
258
 
191
259
 
192
260
 
193
- しかし、
194
-
195
-
196
-
197
- `withCount()`は、`->paginate()`と併用して利用できないことが判明しました。
198
-
199
-
200
-
201
- [【Laravelのissue】withCount(), having() and paginate() together not working](https://github.com/laravel/framework/issues/28476)
202
-
203
-
204
-
205
- そのため、`withCount()`を利用せずに`likes_count`を定義する必要が出てきました。
206
-
207
-
208
-
209
- そして、下記のSQL文をクエリビルダに変換する必要があります。
210
-
211
-
212
-
213
- ```SQL
214
-
215
- SELECT *,count(likes.id) AS likes_count
216
-
217
- FROM posts
218
-
219
- JOIN likes
220
-
221
- on posts.id = likes.post_id
222
-
223
- GROUP BY posts.id
224
-
225
- ```
226
-
227
-
228
-
229
261
  今はSQLで解決しようとしてますが、これが難しければ集計テーブルを作成し、それを`join`で結合するかも検討しています。
230
262
 
231
263