laravel / ideas

Issues board used for Laravel internals discussions.
939 stars 28 forks source link

[Proposal] Make whereJsonDoesntContain() with array input behaviour more intuitive #1668

Open Dankirk opened 5 years ago

Dankirk commented 5 years ago

Story You can fetch rows where a json column has 'item1' and 'item2' with the following method whereJsonContains('column', ['item1', 'item2']);

However, if you wanted to do the opposite, a the simple query below is not sufficient. whereJsonDoesntContain('column', ['item1', 'item2']); This query might return rows containining, for example 'item3' and 'item2'.

To get the expected result, where neither item1 or item2 are present, you have to do this in a foreach loop instead

foreach (['item1', 'item2'] as $item) {
   whereJsonDoesntContain('column', $item);
}

Speculation As I understand it the query below currently returns rows that don't contain item1 AND item2, but intuition tells this should return rows that don't contain item1 OR item2. whereJsonDoesntContain('column', ['item1', 'item2']);

Preserve functionality To preserve the current behaviour where query by combination of values is preferred, one should use the where() method with a callback as usual with a orWhereJsonDoesntContain() (notice the or)

where(function($q) use ($items) { 
    foreach ($items as $item) {
        $q->orWhereJsonDoesntContain('column', $item);
    }
});

Reproduction of current behavior

  1. Have a table with a json column called 'column' and a single row with json value: ['item1','item2']
  2. Run whereJsonDoesntContain('column', ['item2', 'item3']);
  3. This returns you the single row containing item2
staudenmeir commented 5 years ago

(I added these methods.)

I see your point, but I don't think we should change this. The current behavior wasn't really a deliberate decision: It's the result of negating the json_contains() clause with not.

That's why whereJsonDoesntContain() only returns rows "that don't contain item1 AND item2".