从预先加载的 laravel 集合中加载特定的列
Posted
技术标签:
【中文标题】从预先加载的 laravel 集合中加载特定的列【英文标题】:Load specific columns from eager loaded laravel collection 【发布时间】:2021-09-28 15:00:42 【问题描述】:考虑书籍和作者的关系。每本书 belongsTo 一位作者和 1 个作者 hasMany 本书。 Books 表具有(Id、Title、Version 等)等字段,作者具有(Id、Name、Address 等)等字段。注意 DB 列不遵循默认的 laravel 命名约定。
现在;我想从两个表中获取 一些字段。更具体一点,我想要 title、version、name 和 address 字段。 这是所需的输出:
Title: "Oxford Maths",
Version: "2.5",
author: "John Doe",
第一次试用:
return Book::with('author')->get()->map(function ($book)
return collect($book)->only(
[
'Title',
'Version',
"author"
]);
);
第一次试验输出:
Title: "Oxford Maths",
Version: "2.5",
author:
Id: 1,
Name: "John Doe",
Address: "Tanzania",
deleted_at: null
第二次试用:试过这个;
return Book::with([
'author' => function($query)
$query->select('Name','Id');
])->get()->map(function ($data)
return collect($data)->only(
[
'Title',
'Version',
"author"
]);
);
还有这个;
return Book::with('authority:name,Id')->get()->map(function ($data)
return collect($data)->only(
[
'Title',
'Version',
"author"
]);
);
第二次试验输出:
Title: "Oxford Maths",
Version: "2.5",
author:
Name: "John Doe",
Id: 1
第三次试用:
return Book::with([
'author' => function($query)
$query->select('Name'); // *Removed foreignKey*
])->get()->map(function ($data)
return collect($data)->only(
[
'Title',
'Version',
"author"
]);
);
第三次试验输出:
Title: "Oxford Maths",
Version: "2.5",
author: null
我可以做些什么来获得所需的输出?
【问题讨论】:
Book::with('author : title, version, name , address, author_id')->get();这有帮助吗? @psa 试过但没有用。 Book 表中是否有 author_id 字段? 是的,有一个,关系是一对多的。 laravel.com/docs/8.x/… 【参考方案1】:当然,您可以事后在集合上执行此操作,但直接在查询上执行此操作更有意义。你试图在你的第三次试验中反映这一点。但是,在我看来,这是 Laravel behaves a bit odd。为了进行预加载,您需要外键。尽管这是合乎逻辑的,但人类还是会忘记这一点。但是如果你忘记包含外键,Laravel 不会告诉你这一点,而是返回 null
。因此,请确保所有必要的主键和外键始终包含在您的关系中。
return Book::with([
'author' => function($query)
$query->select('id', 'Name'); // *Removed foreignKey*
])->get([ 'title' , 'version' ]);
有一件事,当一个关系应该主要只返回它的一个值时,我喜欢做:
class Author extends Model
public function __toString()
return $this->Name;
要以这种方式自动序列化,您可以将__toString()
更改为jsonSerialize()
class Author extends Model implements JsonSerializable
public function jsonSerialize()
return $this->Name;
【讨论】:
我试过这个。然而,我得到了第三次试验输出。如何在此处添加 author_name?->get([ 'title' , 'version' ]);
author_name
是列还是访问器,还是还没有?
我的意思是希望输出中的作者姓名。 author_name 不是列,而 name 是 authors 表中的列。
由于某些原因,在使用这种方法时会得到相同的结果。我决定采用延迟加载方法而不是急切加载。看我的回答。【参考方案2】:
也许对你有帮助
在模型中
protected $appends = [
'author_name', 'address'
];
protected $fillable = [
'title',
'version',
];
public function author()
return $this->belongsTo(Author::class);
public function getAuthorNameAttribute()
return $this->author->name;
public function getAddressAttribute()
return $this->author->address;
在控制器中使用这个
return Book::query()->with('author')->first()->makeHidden(['author','author_id']);
输出:
"id": 1,
"title": "book",
"version": "v1",
"created_at": null,
"updated_at": null,
"author_name": "komeyl",
"address": "Iran"
【讨论】:
感谢您的贡献,但您能否将代码添加为文本而不是图像,以确保即使图像被删除,您的答案仍然有用?【参考方案3】:我最终使用了@komeyl-dev 建议的技巧。这是示例代码:
//Book.php
class Book extends Model
protected $appends = ['author_name']; // appended so I can access it as json
public function author()
return $this->belongsTo(Author::class,'author_id');
public function getAuthorNameAttribute()
return $this->author->name;
//Testing in web.php (Note: No eager loading here)
Route::get('url', function ()
return Book::get()->map(function ($data)
return collect($data)->only(
[
'Title',
'Version',
"author_name"
]);
);
);
谢谢@shaedrich 和@komeyl-dev
【讨论】:
以上是关于从预先加载的 laravel 集合中加载特定的列的主要内容,如果未能解决你的问题,请参考以下文章
我想从我的 CSV 文件中加载特定的列数据(MySQL 8.0)
有啥方法可以避免在 Laravel 5.7 Eloquent 中加载父级时加载这些 $with 模型?