As of PostgreSQL 9.4, you can use the ? operator:
select info->>'name' from rabbits where (info->'food')::jsonb ? 'carrots';
You can even index the ? query on the "food" key if you switch to the jsonb type instead:
alter table rabbits alter info type jsonb using info::jsonb;
create index on rabbits using gin ((info->'food'));
select info->>'name' from rabbits where info->'food' ? 'carrots';
Of course, you probably don't have time for that as a full-time rabbit keeper.
Update: Here's a demonstration of the performance improvements on a table of 1,000,000 rabbits where each rabbit likes two foods and 10% of them like carrots:
d=# -- Postgres 9.3 solution
d=# explain analyze select info->>'name' from rabbits where exists (
d(# select 1 from json_array_elements(info->'food') as food
d(# where food::text = '"carrots"'
d(# );
Execution time: 3084.927 ms
d=# -- Postgres 9.4+ solution
d=# explain analyze select info->'name' from rabbits where (info->'food')::jsonb ? 'carrots';
Execution time: 1255.501 ms
d=# alter table rabbits alter info type jsonb using info::jsonb;
d=# explain analyze select info->'name' from rabbits where info->'food' ? 'carrots';
Execution time: 465.919 ms
d=# create index on rabbits using gin ((info->'food'));
d=# explain analyze select info->'name' from rabbits where info->'food' ? 'carrots';
Execution time: 256.478 ms
Answer from Snowball on Stack OverflowAs of PostgreSQL 9.4, you can use the ? operator:
select info->>'name' from rabbits where (info->'food')::jsonb ? 'carrots';
You can even index the ? query on the "food" key if you switch to the jsonb type instead:
alter table rabbits alter info type jsonb using info::jsonb;
create index on rabbits using gin ((info->'food'));
select info->>'name' from rabbits where info->'food' ? 'carrots';
Of course, you probably don't have time for that as a full-time rabbit keeper.
Update: Here's a demonstration of the performance improvements on a table of 1,000,000 rabbits where each rabbit likes two foods and 10% of them like carrots:
d=# -- Postgres 9.3 solution
d=# explain analyze select info->>'name' from rabbits where exists (
d(# select 1 from json_array_elements(info->'food') as food
d(# where food::text = '"carrots"'
d(# );
Execution time: 3084.927 ms
d=# -- Postgres 9.4+ solution
d=# explain analyze select info->'name' from rabbits where (info->'food')::jsonb ? 'carrots';
Execution time: 1255.501 ms
d=# alter table rabbits alter info type jsonb using info::jsonb;
d=# explain analyze select info->'name' from rabbits where info->'food' ? 'carrots';
Execution time: 465.919 ms
d=# create index on rabbits using gin ((info->'food'));
d=# explain analyze select info->'name' from rabbits where info->'food' ? 'carrots';
Execution time: 256.478 ms
You could use @> operator to do this something like
SELECT info->>'name'
FROM rabbits
WHERE info->'food' @> '"carrots"';
Try the following:
var categories = [
{catValue:1, catName: 'Arts, crafts, and collectibles'},
{catValue:2, catName: 'Baby'},
{catValue:3, catName: 'Beauty and fragrances'},
{catValue:4, catName: 'Books and magazines'},
{catValue:5, catName: 'Business to business'},
{catValue:6, catName: 'Clothing, accessories, and shoes'},
{catValue:7, catName: 'Antiques'},
{catValue:8, catName: 'Art and craft supplies'},
{catValue:9, catName: 'Art dealers and galleries'},
{catValue:10, catName: 'Camera and photographic supplies'},
{catValue:11, catName: 'Digital art'},
{catValue:12, catName: 'Memorabilia'}
];
var categoriesJson = JSON.stringify(categories);
var mainCat = ['Arts, crafts, and collectibles', 'Baby' , 'Antiques']
$.each(JSON.parse(categoriesJson) , function (key, value) {
if(mainCat.indexOf(value.catName) > -1){
console.log('Exists: ' +value.catName)
}
else{
console.log('Does not exists: ' +value.catName)
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I would filter the initial data array to get the array of matching categories:
var matchedCategories = categories.filter(i => mainCat.indexOf(i.catName) >= 0);
Then you could do what you need by iterating this sub-array.
On MySQL 5.7.8+ you can perform a JSON_CONTAINS for each separate value:
SELECT *
FROM Schedule
WHERE ( JSON_CONTAINS(Days, '1')
OR JSON_CONTAINS(Days, '2')
OR JSON_CONTAINS(Days, '6')
)
When the values to be searched for are stored in a PHP variable -- as in your question -- then you could build the above SQL like this:
$DaysVar = $_GET['Days'];
$condition = implode(" OR ", array_map(function($day) {
return "JSON_CONTAINS(Days, '".intval($day)."')";
}, $DaysVar));
$sql = mysqli_query($db, "
SELECT ScheduleID,
Days
FROM Schedule
WHERE ($condition)
");
To avoid SQL injection, you should better prepare your statement creating a string like with substr(str_repeat(" OR JSON_CONTAINS(Days, ?)", count($DaysVar)), 3) and then call mysqli_prepare on it, then bind, ...etc.
MySQL 8.*
Since MySQL 8 you can use JSON_OVERLAPS:
SELECT *
FROM Schedule
WHERE JSON_OVERLAPS(Days, '$DaysVar')
Again, you would better prepare the statement (with a ? placeholder), then bind $DaysVar to it, and finally execute it.
Probably you found a solution, but for those looking for an answer in the future:
There is now JSON_OVERLAPS(), which in your example you can just swap out for JSON_CONTAINS().
https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-overlaps