在 Laravel 中从数据库存储和加载 JSON 的最佳方法

Posted

技术标签:

【中文标题】在 Laravel 中从数据库存储和加载 JSON 的最佳方法【英文标题】:Best way to store and load JSON from database in Laravel 【发布时间】:2021-07-17 03:34:04 【问题描述】:

我正在尝试将 json 存储到数据库中并加载回来

我试图存储

name: "John", age: 31, city: "New York"

它存储正确。我检查了数据库,它显示正确。

姓名:“约翰”,年龄:31,城市:“纽约”

我一直在看风景

"name: \"John\", age: 31, city: \"New York\""

这是我的代码。

public function store()


    $paste             = new Paste;
    $paste->uuid       = Str::uuid()->toString();
    $paste->data       = trim(Request::get('data',''));
    $paste->save();

    return Redirect::to('/paste/'.$paste->uuid)->with('success', 'Created');



public function show($uuid)

    $paste  = Paste::where('uuid',$uuid)->first();
    return response()->json($paste->data);

有什么提示吗?

此处可重现

https://www.bunlongheng.com/paste


试试#2

如果我这样做了

public function show($uuid)



    $paste  = Paste::where('uuid',$uuid)->first();
    return View::make('layouts.fe.pastes.show', get_defined_vars());


在我看来,我只有这一行

!!$paste->data!!

我得到的数据与我现在提交的数据相同。

name: "John", age: 31, city: "New York"

但是浏览器将其检测为文本,而不是响应 JSON,这违背了我想要做的事情的目的。


试试#3

public function show($uuid)

    $paste  = Paste::where('uuid',$uuid)->first();
    return response()->json(stripslashes($paste->data));
    

结果

"name: \"John\", age: 31, city: \"New York\""

试试#4

public function show($uuid)

    $paste  = Paste::where('uuid',$uuid)->first();
    return View::make('layouts.fe.pastes.show', get_defined_vars());

查看

 json_encode($paste->data, JSON_UNESCAPED_SLASHES) 

结果

"name: \"John\", age: 31, city: \"New York\""

尝试#5

我认为问题在于存储...而不是加载和渲染。

我试过了

return response()->json($paste);

我的 JSON 解析器检测到它...


"id": 11,
"status": 0,
"uuid": "0c40f97d-7d98-42c6-864e-71d3ed81eed3",
"name": "n6ou",
"password": "",
"expiration": "",
"type": "json",
"data": "name: \"John\", age: 31, city: \"New York\"",
"created_at": "2021-04-22T22:53:11.000000Z",
"updated_at": "2021-04-22T22:53:11.000000Z"

这是我以前储存的

$paste->data       = trim(Request::get('data',''));
$paste->save();

尝试#6

对于那些怀疑我的数据/内容的人

我尝试在 Pastebin 中粘贴同一行

已经清理干净了,你可以在下面看到。

https://pastebin.com/raw/r9akUK1v

【问题讨论】:

尝试使用return response()->json(stripslashes($paste->data)); 或者,在你看来试试这个: json_encode($paste->data, JSON_UNESCAPED_SLASHES) 两个都试一下,斜线还在。 试试 json_decode($paste->data) ,这应该可以。 控制器代码是什么样的? 【参考方案1】:

数据库

在您的数据库迁移中添加:

$table->json('data'); // Recommended. Supported in mysql since version 5.7.8

$table->text('data');

推荐使用 JSON 列类型,因为它允许您对 JSON 数据执行 SQL 查询。见MySQL JSON Data Type

模型:铸造属性

下一个问题是您需要能够将数据转换为 php 数组。

这是通过修改模型中的 casts 属性来完成的:

class Paste extends Model 
    protected $casts = [
        'data' => 'array'
    ];

更多信息请参见Array and JSON Casting。

现在您可以将数据作为 PHP 数组保存到属性中,并为其分配一个 PHP 数组。

 $paste = Paste::first();
 dump($paste); // Returns a PHP array     

 $paste->data = ['some-data' => 20, 'score' => 500];
 $paste->save();

在内部,当它保存数据时,它会自动将其转换为 JSON 字符串并以正确的格式保存在数据库中。

存储方法

当以 JSON 格式接收输入时,很大程度上取决于您希望如何传递数据,

1.发送 JSON 内容类型的表单数据(推荐)

我的建议是在 POST 正文中以 JSON 格式发送整个数据,如下所示:

Content-Type: application/json
Body:

   "data": 
      "name": "John",
      "age": 31,
      "city": "New York"
   ,
   "someOtherField": "Hello!"

您的 store() 方法现在应该是(我还添加了验证码):

public function store()

    $this->validate($request, [
        'data' => ['required', 'array'],
        'data.*.name' => ['required', 'string'],
        'data.*.age' => ['required', 'int'],
        'data.*.city' => ['required', 'string'],
    ]);
    
    $paste = new Paste();
    $paste->uuid = Str::uuid()->toString();
    $paste->data = $request->post('data'); // No need to decode as it's already an array
    $paste->save();

    return Redirect::to("/paste/$paste->uuid")
        ->with('success', 'Created');

2。使用表单参数发送表单数据

但是,如果您坚持通过查询参数或表单参数发送数据,请注意这些只能发送字符串。因此,您需要将 JSON 字符串的编码版本发送到持久数据类型,如下所示:

Form Params:
- data: '"name": "John", "age": 31, "city": "New York"'
- someOtherField: "Hello!"

store 方法现在看起来像这样:

    $this->validate($request, [
        'data' => ['required', 'json'], // I'm unsure if data is required
    ]);
    
    $data = json_decode($request->post('data'), true, JSON_THROW_ON_ERROR); // Needs to be decoded
    
    // validate $data is correct
    Validator::make($data, [
        'name' => ['required', 'string'],
        'age' => ['required', 'int'],
        'city' => ['required', 'string'],
    ])->validate();
    
    
    $paste = new Paste();
    $paste->uuid = Str::uuid()->toString();
    $paste->data = $data;
    $paste->save();

    return Redirect::to("/paste/$paste->uuid")
        ->with('success', 'Created');

显示方法

您的 show 方法无需更改:

public function show($uuid)

    $paste = Paste::where('uuid', $uuid)->first();
    return response()->json($paste->data);

【讨论】:

这一行,$data = json_decode($request->post('data')); 不断将我的数据输入 json 设为 null。 你是如何调用你的 API 的。也许显示你的 javascript 或 curl 代码? 如果您使用查询字符串,它将是$request->query('data') 我已经更新了这条线。犯了一个小错误,没有把 true 作为第二个参数。如果数据不是有效的 JSON 字符串,它也不会抛出错误。【参考方案2】:

1- 您的列需要是 json 类型

$table->json('data');

2- 在您的模型中,您需要将列转换为数组

  protected $casts = ['data' => 'array'];

3- 向你的控制器发送数据值必须是一个数组,这样你就可以对它使用数组 Laravel 验证:

[
  'data' => 'required|array',
  'data.*.name' => 'required'
   ....
]

4- 当您存储数据时,它将被自动解析,当您检索数据列时,它将被转换为数组

【讨论】:

让我试试这个建议 我认为这种方法是使用 JSON 的最佳方式。一个补充(假设 OP 使用 MySQL DB):旧的 MySQL 服务器不支持 JSON 类型。所以 MySQL @GordonFreeman 当然对于旧版本,longText 是解决方案,但在这种情况下我不确定 elequont @PsyLogic Eloquent 处理得很好。旧项目没有问题。无论实际的数据库字段类型如何,protected $casts 都会发挥作用。我能想到的唯一缺点是,无法从 DB 级别的 JSON 类型字段中受益(在 JSON 中搜索等)。 感谢您的确认,但由于 JSON 方法已添加到 5.7+,因此确定它不适用于搜索,因此您需要在您的数据库中使用自定义函数或返回列值并在你的后端(不推荐)【参考方案3】:
    使用->json()作为存储JSON数据的迁移方式(https://laravel.com/docs/8.x/migrations#column-method-json) 请参阅“Array & JSON Casting”(https://laravel.com/docs/8.x/eloquent-mutators#array-and-json-casting) 了解如何准备数据

我知道答案不像其他人那样在段落中,但我喜欢让它简单明了。这是最好的解决方案吗?没有人能告诉你,也不能证明这一点?这种方法行得通吗,没人能告诉你,也不能证明,但至少它会提高你的成功率。让我知道是否还有什么我可以帮忙的!祝你好运

【讨论】:

【参考方案4】:

如果您想将数据作为 json 存储在 DB 上并恢复它,只需执行以下操作(我总是使用这种方式):

1- 将数据添加到数组中:

$data["name"] = "John";
$data["age"] = 31;
$data["city"] = "New York";

2- 对数组进行编码并将其添加到数据库中(可以将其存储为文本)

$encodedData = json_encode($data);

3- 如果您想添加嵌套的 json 数据,只需将您的数组设为嵌套数组即可。

4- 当您恢复数据时,只需使用 json_decode 对其进行解码

【讨论】:

我必须根据用户提供的数据来存储...请阅读我的帖子 对不起,我给你这个是因为你说问题出在存储上。来自request的json数据默认没有问题,如果问题依然存在,可以用它来填充响应数据到视图中 用户将提供 json 文本。【参考方案5】:

只需将此添加到您的模型中。

protected $casts = [
    'data' => 'object'
];

然后你可以像这样进入你的视图:

 $data->data->name 

【讨论】:

以上是关于在 Laravel 中从数据库存储和加载 JSON 的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在laravel刀片中从json解码中回显键名和键值

在选择选项 html 中从数据库加载数据 - Laravel

如何在 Laravel 中从 json 索引计数

在我的 laravel 应用程序中从我的 PHP API 获取 json 响应

在选取器视图中从 JSON 加载数据

在 viewDidLoad 中从 JSON 加载数据不起作用