question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Support for more conditions in findOne

See original GitHub issue

Problem

I think Prisma should support “nested where” query syntax. This is where two or more tables that are joined both have a where clause against them.

For example, let’s say I’m building a CRM where a User has many Contacts and a Contact can have many Notes:

model User {
  id          Int        @default(autoincrement()) @id
  email       String     @unique
  name        String?
  contacts    Contact[]
}

model Contact {
  id        Int       @default(autoincrement()) @id
  user      User      @relation(fields: [userId], references: [id])
  userId    Int
  name      String?
  email     String?
  notes     Note[]
}

model Note {
  id        Int      @default(autoincrement()) @id
  contact   Contact  @relation(fields: [contactId], references: [id])
  contactId Int
  text      String
}

In the simplest case I want to pull a note by ID, but only if the proper user owns that note. So let’s say the user is ID 123 and they want to view note 456. In regular SQL I might do something like

SELECT Note.*
FROM   Note INNER JOIN Contact ON Note.contactId = Contact.id
WHERE  Note.id = 456 AND Contact.userId = 123

So if the Note.id is correct, but the proper user doesn’t own that note, this will return null. Right now when using Prisma I need to manually add a conditional to check the status of that ID, something like:

const note = await db.note.findOne({
  where: { id },
  include: { contact: { select: { userId: true } } },
})

if (note.contact.userId === currentUser.id) {
  return note
} else {
  return null
}

(Notice that if I want this function to only return the note and not included contact detail, I also need to delete note.contact).

Suggested solution

Similar to the ability to add select and include objects to relations, allowing setting a where object that could add that nested where. Then the above code then becomes a single statement:

return db.note.findOne({
  where: { id },
  include: { contact: { where: { userId: currentUser.id } } }
})

(In this case I would still need to delete the included note.contact in order to only return the note data.)

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:14 (9 by maintainers)

github_iconTop GitHub Comments

6reactions
cannikincommented, Jul 7, 2020

I am not sure how we will maintain the uniqueness of findOne here though.

Question: why is this uniqueness constraint part of findOne anyway? This isn’t a limitation of SQL…are you trying to optimize something in the code itself? Why not just call findMany behind the scenes and then return the first result?

This is what Rails ActiveRecord does—find (equivalent to findOne) is just using where (equivalent to findMany) behind the scenes and then adding LIMIT 1 so you only ever get 1 result. If it’s not the one you were expecting then you weren’t selecting by a unique column, but it doesn’t force you to use a unique column, that’s up to you.

4reactions
pantharshit00commented, Jul 7, 2020

Yeah, I actually agree with you here. I will raise this internally to the team 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Mongoose findOne with Multiple Conditions - ObjectRocket
findOne () with multiple conditions ... Go through all the documents in the details collection. The first and third document has the same...
Read more >
How to do simple mongoose findOne with multiple conditions?
Try using the mongoose promise system ( .exec() ). The query inside .findOne() should be a single object. User .findOne({email: email ...
Read more >
db.collection.findOne() — MongoDB Manual
Returns one document that satisfies the specified query criteria on the collection or view. If multiple documents satisfy the query, this method returns...
Read more >
MongoDB findOne Example - DigitalOcean
MongoDB findOne() method returns only one document that satisfies the criteria entered. If the criteria entered matches for more than one ...
Read more >
Mongoose v6.8.1: Query Population
Field Selection; Populating Multiple Paths; Query conditions and other ... findOne({ title: 'Casino Royale' }). populate('author'). exec(function (err, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found