我有一个“静态”模型。它包含带有有关其各种信息的游戏。用户可以评论具有多态关系的游戏。问题是我想获取已被评论的10个最新游戏,以及该评论的用户。因此,Game
与Users
没有关系。
我设法解决了这个问题
$games = Game::join('comments', 'games.id', '=', 'comments.commentable_id')
->where('comments.commentable_type', Game::class)
->latest('comments.created_at')
->groupBy('games.id')
->take(10)
->withCount('comments')
->get()->each(function($game){
$game->comment = $game->comments()->orderBy('created_at', 'desc')->first();
$game->user = User::find($game->comment->user_id);
return $game;
});
但这会创建很多查询,我想急于加载,没有每个人都在谈论的N + 1问题。
我还有另一种解决方案,可以将此功能添加到Game
class Game extends Model {
public function latestComment() {
return $this->morphOne(Comment::class, 'commentable')->latest();
}
}
运行查询$games = Game::withCount('comments')->with(['latestComment.user'])->take(10)->get();
但是似乎此查询无法获取用户。仅获取第一个用户。并且comments_count
(withCount()
)仅返回第一个结果的值。
所以我被卡住了!
预期结果 用该游戏的最新评论,该游戏的评论总数,用户的最新评论来加载10个最新游戏-渴望加载所有内容以避免n + 1问题。
有可能吗? ps。准备了一个sqlfiddle http://www.sqlfiddle.com/#!9/c07570
修改
似乎这个问题中的第二个查询“ takes”(take(10)
)从游戏表中取出前10个游戏,无论它们是否有注释。如果我对ID为20-30的游戏有15条评论,则查询将检查ID为1到10的游戏。
如果我运行问题中的第二个查询,而注释表中只有小提琴数据。结果10将包含ID为10,没有用户,没有comments_count
等的游戏。
答案 0 :(得分:0)
您可以使用经过修改的import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
import MapKit
class EmployeeTableViewController: UITableViewController, CLLocationManagerDelegate {
@IBOutlet weak var jobsAvailableMap: MKMapView!
var jobRequests : [DataSnapshot] = []
var locationManager = CLLocationManager()
var employeeLocation = CLLocationCoordinate2D()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
Database.database().reference().child("JobRequests").observe(.childAdded) { (snapshot) in
if let jobRequestDictionary = snapshot.value as? [String:AnyObject] {
if let employeeLat = jobRequestDictionary["employeeLat"] as? Double {
} else {
self.jobRequests.append(snapshot)
self.tableView.reloadData()
}
}
}
Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { (timer) in
self.tableView.reloadData()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let coord = manager.location?.coordinate {
employeeLocation = coord
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return jobRequests.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "jobRequestCell", for: indexPath)
let snapshot = jobRequests[indexPath.row]
if let jobRequestDictionary = snapshot.value as? [String:AnyObject] {
if let email = jobRequestDictionary["email"] as? String {
if let lat = jobRequestDictionary["lat"] as? Double {
if let lon = jobRequestDictionary["lon"] as? Double {
let employeeCLLocation = CLLocation(latitude: employeeLocation.latitude, longitude: employeeLocation.longitude)
let employerCLLocation = CLLocation(latitude: lat, longitude: lon)
let distance = employeeCLLocation.distance(from: employerCLLocation) / 1000
let roundedDistance = round(distance * 100) / 100
cell.textLabel?.text = "\(email) - \(roundedDistance)km away"
}
}
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let snapshot = jobRequests[indexPath.row]
performSegue(withIdentifier: "acceptSegue", sender: snapshot)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let acceptVC = segue.destination as? AcceptJobViewController {
if let snapshot = sender as? DataSnapshot {
if let jobRequestDictionary = snapshot.value as? [String:AnyObject] {
if let email = jobRequestDictionary["email"] as? String {
if let lat = jobRequestDictionary["lat"] as? Double {
if let lon = jobRequestDictionary["lon"] as? Double {
acceptVC.requestEmail = email
let location = CLLocationCoordinate2D(latitude: lat, longitude: lon)
acceptVC.requestLocation = location
acceptVC.employeeLocation = employeeLocation
}
}
}
}
}
}
}
@IBAction func logoutTapped(_ sender: Any) {
try? Auth.auth().signOut()
navigationController?.dismiss(animated: true, completion: nil)
}
}
来获取最新的withCount()
:
comments.created_at
答案 1 :(得分:0)
我将直接访问评论表/模型,查询最近的10条评论,pluck
游戏ID,并使用它们用whereIn
查询游戏模型/表。
还向游戏查询中添加selectRaw('(SELECT COUNT(*) FROM comments where ...) as commentCount')