Laravel查询构建器方法及字段存储格式选型技术咨询
关于Laravel产品表操作的技术建议
嘿,我来帮你把这些问题捋清楚,一步步说哈~
一、替代PHP数组函数的Eloquent/查询构建器方案
你现在把数据库字段拉到PHP里用array_push/array_search/array_splice处理,其实完全没必要——Laravel和数据库本身就提供了更高效、更简洁的方式,不用把数据拿到应用层折腾:
- 判断元素是否存在:直接用数据库的JSON查询或字符串匹配函数,在数据库层面完成判断,不用拉数据。
- 插入/删除元素:用数据库的JSON操作函数,或者借助Eloquent的模型特性直接操作数组,自动同步到数据库。
二、A_product列存储格式:JSON完胜逗号分隔字符串
直接给结论:优先选择JSON格式存储,原因如下:
- 类型安全:JSON是数据库原生支持的类型(比如MySQL的
JSON类型),能明确存储数组结构,而逗号分隔的字符串本质是文本,容易出现格式错误(比如多逗号、空格、重复值)。 - 查询更灵活:Laravel专门提供了
whereJsonContains这类JSON查询方法,比FIND_IN_SET更强大,还能处理嵌套结构(以后扩展也方便)。 - 开发效率高:在Eloquent模型里设置
$casts属性后,Laravel会自动把JSON字段转成PHP数组,你直接操作数组就行,不用自己拆字符串、转格式。 - 可扩展性强:如果以后需要给每个产品项加额外属性(比如数量、备注),JSON可以直接存对象数组,逗号分隔字符串根本做不到。
逗号分隔字符串属于数据库设计的反模式,后期维护成本极高,除非有特殊历史原因,否则坚决不推荐。
三、优化“判断id=1的A_product是否包含3”的代码
你当前的代码有个小错误:in_array("3")少了第二个参数(要传入拆分后的数组),而且这种方式效率低——不如直接在数据库层面完成判断:
方案1:JSON格式下的优雅实现
假设A_product存的是JSON数组(比如[4,5,8,9]),先在Product模型里加一行:
protected $casts = [ 'A_product' => 'array', // 自动把JSON转成PHP数组 ];
然后判断代码可以写成:
// 用模型的方式 $product = Product::find(1); $A_result = collect($product->A_product)->contains(3) ? '1' : '0'; // 或者用查询构建器直接查 $A_result = DB::table('product') ->where('id', 1) ->whereJsonContains('A_product', 3) ->exists() ? '1' : '0';
两种方式都不用把字段拉到PHP里拆数组,简洁又高效。
方案2:如果暂时用逗号分隔字符串(不推荐)
可以用MySQL的FIND_IN_SET函数直接查询:
$A_result = DB::table('product') ->where('id', 1) ->whereRaw('FIND_IN_SET(?, A_product)', [3]) ->exists() ? '1' : '0';
这种方式比你原来拆数组的方法效率高,因为不用传输数据到应用层。
四、插入/修改元素的操作建议
1. JSON格式下的操作(推荐)
追加元素
用模型的话超级简单,直接操作数组再保存:
$product = Product::find(1); $product->A_product[] = 12; // 直接追加元素 $product->save(); // Laravel自动转成JSON存回数据库
如果想用查询构建器批量更新:
DB::table('product') ->where('id', 1) ->update([ 'A_product' => DB::raw('JSON_ARRAY_APPEND(A_product, "$", ?)'), ], [12]);
删除元素
模型方式更直观:
$product = Product::find(1); // 过滤掉要删除的元素,重新赋值 $product->A_product = collect($product->A_product)->reject(function ($item) { return $item == 5; })->values()->toArray(); $product->save();
查询构建器方式用数据库函数:
DB::table('product') ->where('id', 1) ->update([ 'A_product' => DB::raw('JSON_REMOVE(A_product, JSON_UNQUOTE(JSON_SEARCH(A_product, "one", ?)))'), ], [5]);
2. 逗号分隔字符串下的操作(不推荐)
这种方式非常繁琐,容易出错,举个例子:
追加元素(要先判断是否存在,避免重复)
DB::table('product') ->where('id', 1) ->whereRaw('NOT FIND_IN_SET(?, A_product)', [12]) ->update([ 'A_product' => DB::raw('CONCAT(A_product, ",?")'), ], [12]);
删除元素(容易误删类似值,比如删5会把15也改掉)
DB::table('product') ->where('id', 1) ->update([ 'A_product' => DB::raw('TRIM(BOTH "," FROM REPLACE(CONCAT(",", A_product, ","), ",5,", ","))'), ]);
这种写法维护起来太痛苦,真心不建议用。
五、终极建议:考虑数据库规范化
如果你的产品项需要频繁查询、修改,最好的方案是规范化数据库结构——创建一个关联表,比如product_associations:
| id | product_id | product_value | type |
|---|---|---|---|
| 1 | 1 | 4 | A |
| 2 | 1 | 5 | A |
| 3 | 1 | 3 | B |
| ... | ... | ... | ... |
然后在Product模型里定义关联:
public function aProducts() { return $this->hasMany(ProductAssociation::class, 'product_id') ->where('type', 'A'); } public function bProducts() { return $this->hasMany(ProductAssociation::class, 'product_id') ->where('type', 'B'); }
这种方式的好处:
- 可以给
product_value加索引,查询效率爆表。 - 操作更符合数据库设计规范,不会有JSON/字符串数组的各种坑。
- 支持更复杂的查询(比如统计某个产品值出现的次数)。
当然,如果你的业务场景非常简单,JSON格式也足够用,但规范化是长期来看最靠谱的方案。
内容的提问来源于stack exchange,提问作者robspin
相关产品推荐
相关产品推荐

