21

So in Laravel 5 there's the handy thing called JSON Where Clauses using MySQL's new ability to store and fetch JSON stored in a column:

User::where('meta->colors', 'red')->get()

would return all rows, where colors in the column meta would be set to red.

Now let's say colors is not a string, but an array containing multiple colors (colors => ['red', 'blue', 'green']).

What would be an efficient way to retrieve all rows, where colors contains e.g. the value red?

3
  • Did you mean $x = ['red', 'blue', 'green']; or $x = (colors => ['red', 'blue', 'green']) ? Commented Sep 5, 2017 at 12:45
  • Have you tried WhereIn condition ??? Commented Sep 5, 2017 at 12:46
  • To clarify: The user has a property / column, lets say it's called meta, which contains the following JSON: { "colors": ["red", "blue", "green"] } And I want to retrieve it, if colors contains the value red. Commented Sep 5, 2017 at 12:51

4 Answers 4

25

JSON_CONTAINS() does exactly what you're looking for:

JSON_CONTAINS(target, candidate[, path])

Indicates by returning 1 or 0 whether a given candidate JSON document is contained within a target JSON document, or—if a path argument was supplied—whether the candidate is found at a specific path within the target. — 12.16.3 Functions That Search JSON Values

Currently, Laravel's query builder does not provide a corresponding API. There's an open internals proposal for it though.

In the meantime, you can execute a raw query:

\DB::table('users')->whereRaw(
    'JSON_CONTAINS(meta->"$.colors", \'["red"]\')'
)->get();

Which would return all users that have "red" in their meta->colors JSON field. Note that the -> operator requires MySQL 5.7.9+.

You can also call the whereRaw() directly on an Eloquent model.

Laravel 5.6

As of the 5.6 release, Laravel's query builder contains a new whereJsonContains method.

Sign up to request clarification or add additional context in comments.

5 Comments

how do you replace this ["red"] with array variable?
That's already an array, you can add items to it. Look at the JSON_CONTAINS documentation for more information on this.
It looks like Laravel 5.7 will include whereJsonContains for MySQL, PostgreSQL, and SQL Server: github.com/laravel/framework/pull/24330
whereJsonContains was introduced in Laravel 5.6
@SamuelReid Updated the answer. Thank you.
6

I think a way would be using the like operator:

User::where('meta->colors', 'like', '%"red"%')

However, this would only work if the values never contain the character " and the delimiters wouldn't change.

Comments

3

An update for this answer, according to MySQL or MariaDb, the correct syntax must be JSON_CONTAINS(@json, 'red', '$.colors'), and is necessary to use JSON_EXTRACT.

So them, the code inside Laravel (for version 5.5 or less).

Like say @Elwin, meta column must contains the following JSON: { "colors": ["red", "blue", "green"] }

User::whereRaw("JSON_CONTAINS(JSON_EXTRACT(meta, '$.colors'), '\"{$color}\"')")

Remember to use double quotes in value sentence.
JSON_CONTAINS(JSON_EXTRACT(meta, '$.colors'), '"red"')

1 Comment

This work perfectly on my Laravel 6.x and mariadb 10.x
-3

The whereIn method verifies that a given column's value is contained within the given array. Try this:

$colorArray = ['red', 'blue', 'green'];

$user = User::whereIn($meta->color, $colorArray)->get();

More about Laravel's whereIn.

2 Comments

I meant basically the other way around: The user object contains an array, and I want to retrieve it, if the user contains the given value.
What OP looks for is totally different from what whereIn yields. See why.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.