【问题标题】:laravel collection sort by json data from databaselaravel 集合按数据库中的 json 数据排序
【发布时间】:2020-09-06 12:58:38
【问题描述】:

我想按价格订购我的所有产品。在 Product 表中有 product_options 列,在该列内我有 json 数据,类似这样;

{"price":390,"discounted_price":26,"quantity":168}

我尝试通过 product_options 订购,但它按字母顺序返回,所以 17 在 1000 之后。看起来我应该为此使用集合函数,但我真的很陌生。

$searchData = DB::table('posts')->where('type','=','product')->whereNotNull('product_options')->orderBy('product_options->price')->get();

当我返回 dd 函数时,它看起来像这样

有人可以帮帮我吗?

【问题讨论】:

标签: laravel sorting collections


【解决方案1】:

只需将 json 属性转换为十进制或整数。

$searchData = DB
    ::table('posts')
    ->where('type', 'product')
    ->whereNotNull('product_options')
    ->orderByRaw("CAST(product_options->>'$.price' AS DECIMAL(10,6))")
    ->get();

【讨论】:

  • 它给出了这个错误 ""SQLSTATE[42000]: 语法错误或访问冲突:1064 你的 SQL 语法有错误;检查与您的 MariaDB 服务器版本相对应的手册,以在第 1 行的 '>'$.price' AS DECIMAL(10,6))' 附近使用正确的语法(SQL:select * from posts where type = product 和 product_options is not null order by CAST(data->'$.price' AS DECIMAL(10,6)))"" 您输入的“数据”是正确的,或者我应该使用我自己的数据名称或 smt 进行编辑?
  • 完全相同的错误,我尝试了 ->> 和 -> 都不起作用,你有什么或她的想法吗?
【解决方案2】:

我找到了一种方法,并在this git hub discussion 上描述了方法。

我所做的基本上是创建了一个作用域,该作用域从模型中获取 SQL 转换类型,以将道具转换为定义的数据类型(或者它将采用默认值)。这允许它按照数据类型的排序方式进行排序。

像这样:

   public function scopeIncludeJson(Builder $query, $attribute, $name = null)
   {
       $attribute = str_replace('->', '.', $attribute);
       $path = explode('.', $attribute);
       // Skip if column isn't JSON. I could probably make use of $casts 
       // by checking if x's cast is 'array'. But I wasn't sure if that's the
       // right way, so let's leave it like this for now.
       if (in_array($path[0], $this->jsonColumns)) {
           $jsonSelector = '$.' . implode(".", array_slice($path, 1));
           $cast = $this->jsonCasts[$attribute] ?? $this->defaultJsonCast;
           return $query->selectRaw("cast(json_value(`$path[0]`, '$jsonSelector') as $cast) as `". (!empty($name) ? $name : $attribute) . "`");
       }
       return $query;
   }

这样我就可以做到:

$items = Model::includeJson('statistics.data.used', 'customName')
    ->orderBy("customName", "desc")
    ->skip($pageIndex - 1) * $pageSize)
    ->take($pageSize)
    ->get();

--- 编辑---

在您的情况下,如果成功实施,只需:

// In model
class Product extends ModelWithJson
{
    // ...
    protected $jsonColumns = [
        'options'
    ];

    public $jsonCasts = [
        'options.price' => 'unsigned int'
    ]
    // ...
}

// In controller
Product::includeJson('options.price', 'price')->orderBy('price')->get()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-29
    相关资源
    最近更新 更多