prisma: "every" relation filter not working as expected
Bug description
Problem 0: “every” relation filter return all the admins that has no permissions at all. (in the n-to-n table exists no records relating this admins with some permission) This admins should not be returned because they has no permissions and the every condition is not completed.
Problem 1 (Query 1): This query return all the admins that have no permissions + all the admins that have permission 1, or 2, or 3, or 1+2+3. This is copletely wrong. It should return only the admins having 1+2+3.
Problem 2 (Query 2): This query is working partially correct returning not the 1,2,3 admins because they don’t complete the every condition but still return all the admins that have no related permissions which is obviously wrong.
How to reproduce
Follow the primsa information below.
Expected behavior
“Every” should return only the admins that complete the condition agains every relation and should ignore the admins that haven’t relations.
“Every + in” should return only admins compliting the all “every” conditions but it works like some and also return all the admins having not related permissions.
Prisma information
Schema
model Admin{
@@map("admins")
id Int @id @default(autoincrement())
email String @unique
name String?
permissions Permission[]
}
model Permission{
@@map("permissions")
id Int @id @default(autoincrement())
slug String
name String
category String
admins Admin[]
}
Query 1
prisma.admin.findMany({
select: {
id: true,
name: true,
email: true,
roles: {
select: {name: true},
},
permissions: {
select: {name: true},
},
},
where: {
permissions: {
every: {
id: {
in: [1, 2, 3]
}
}
}
}
})
Query 2
prisma.admin.findMany({
select: {
id: true,
name: true,
email: true,
roles: {
select: {name: true},
},
permissions: {
select: {name: true},
},
},
where: {
permissions: {
every: {
id: {
gt: 2
}
}
}
}
})
DB
#admins
1 admin@test.com admin
2 admin1@test.com admin1
3 admin2@test.com admin2
4 admin3@test.com admin3
5 admin4@test.com admin4
6 admin5@test.com admin5
#permissions
1 test-1 test 1 test_1
2 test-2 test 2 test_2
3 test-3 test 3 test_3
#_AdminsToPermissions
1 1
1 2
1 3
2 2
3 3
3 1
Environment & setup
- OS: Ubuntu
- Database: PostgresSQL
- Node.js version: v16.14.0
Prisma Version
@prisma/client": "^3.7.0
prisma": "^3.7.0
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 10
- Comments: 32 (10 by maintainers)
@janpio
Yes, because I would assume that the majority of people wouldn’t anticipate that
every
would return records with no relations. I for sure didn’tHi, please do like this:
Add one more
some
just beforeevery
.The question is exactly about “in” + “every” (read my first comment) and that it doesn’t work the way people expect and may cause unexpected bugs. At the end I don’t use prisma anymore because I like to have control and to work logical. If you think that it is logically correct the “in” + “every” to return also records having no relations at all and should work in this way then it’s not a bug and you should close the issue. I have nothing more to say.
In support of the existing API behaviour: it’s mathematically correct because any statement about the members of an empty set is true https://en.wikipedia.org/wiki/Empty_set
Every: “There are no items in this set for which this statement is false” Some: “There is at least one item in this set for which this statement is true” This is why combining
every
andsome
results in the desired behaviour, which is “There is at least one item in this set AND there are no items in this set for which this statement is false”Prisma’s query language is an abstraction over SQL/noSQL so shouldn’t conform to their query language conventions. It’s an ORM for JS so absolutely should align more closely with native JS APIs. For what it’s worth Mongo does exhibit this behaviour too: https://www.mongodb.com/docs/manual/reference/operator/aggregation/allElementsTrue/
Some clarity in the docs here would be great though
Hey, any progress on this? Started migrating my project to prisma and just ran into this
@SevInf If this is the expected behavior, then the docs are kinda misleading:
every
It says: returns all records where match, but it also returns records that don’t have this relation, so they do not match the criteria
And imho
every: [1,2]
should only return records that have both 1+2 relationsAnd again if this is the expected behavior then why is this issue still open?
@janpio Give me an example using SQL language and “in” operator that will return users that have either no permissions, permission 1, permission 2 or permissions 1+2. At the end Prisma is an layer between JS and SQL or noSQL right? The expected behavior should be like SQL or noSQL and not like JS .every function.
agreee with @Tronikelis 。 Are there any plans to fix this problem? Or you don’t think it’s a problem at all。
@apecollector
every
means that condition individually applies to every item in a relationship. What you query does is basically, “Give me all posts, where every tag is both{ name: 'Development', color: 'Blue' }
and{ name: 'Programming', color: 'Pink' }
”. Since conditions are mutually exclusive, you won’t get anything as a response. What you want is: give me all posts, where one of the tags is{ name: 'Development', color: 'Blue' }
and some other tag is{ name: 'Programming', color: 'Pink' }
. Which could be done with a following query:@janpio those few days are actually 43. You don’t need confirmation from @adventurini to reproduce this bug, just take a look at my example. It’s clear enought.
@jdkdev that JS code is exactly how this query would behave (I think you meant to have
.includes(permission)
in this case, not.includes(permission.id)
) with exactly the same behavior described here. You can check this by using following list of admins:in this case, all but the last admin will be returned.
I tried to achieve what you want without using raw queries and the best I could come up with 4.3.1 version is:
This is definitely suboptimal and are where we could’ve done better. If you’d like to stick with raw queries until we can provide something better, here is a better raw query (assuming postgres):
@jdkdev will something like work for you?
I don’t think it’s a bug, it is an expected behavior. Think of it as of following JS equivalent:
every
on an empty list is alwaystrue
. This is consistent with JS, as well with SQL.every: { id: { in: [1, 2, 3]}}
is “return the admins, where every permission id is either 1, 2, 3” which is exactly what happens.