Querying draft and published versions of documents in Sanity
18 replies
Last updated: Mar 30, 2020
R
Hey all, I have an issue with a GROQ query.
There are 2 schemas:
I want to be able to display all the
Before I found out about this "draft" issue, the query was relying on matching the
So far I tried to rely of draft and published versions to have the same
There are 2 schemas:
blogPostand
category. Each document of type
blogPostreferences to a
category.Now, if I edit a category, a new copy of the published document is created with id
drafts.[id_of_published_doc]
I want to be able to display all the
blogPostdocuments for a draft category — what is the best way to query all
blogPostthat reference a category, even when the current category is a draft and not the published document?
Before I found out about this "draft" issue, the query was relying on matching the
_refwith the
_id
*[_type == "category"] { name, "allBlogPosts": *[_type == "blogPost" && category._ref == ^._id ] { title, } }
slug, but the query doesn't seem to work:
*[_type == "category"] { name, "allBlogPosts": *[_type == "blogPost" && category->slug.current == ^.slug.current ] { title, } }
Mar 23, 2020, 9:03 AM
A
Hi
user S
, did you find a solution for this? I’m having the same problem.Mar 27, 2020, 6:53 PM
R
No, I haven't. I was hoping someone from the Sanity team could help!
Mar 27, 2020, 10:05 PM
R
Yes that would be helpful! Maybe
user M
can point us in the right direction?Mar 27, 2020, 10:09 PM
R
Hi both! Just to make sure I’m understanding the issue correctly, could you explain why you might need the draft version of the
I just checked but it seems like the reference to the
Finally, when querying for all categories through
What am I missing to help you guys?
🙂
categorydocument for the
blogPostreference?
I just checked but it seems like the reference to the
categorymaintains the original, non-draft
_idand the original
categorydocument with the non-draft
_idstill exists too (as you said, it’s a copy), so it continues to function correctly. Also, even though a
categoryis in draft status, it will still add the non-draft
_idto the
_reffield when adding the category as a reference.
Finally, when querying for all categories through
*[_type == "category"]{_id}, it gives both the non-draft and the draft version. You can filter out the draft versions though:
*[_type == 'category' && !(_id in path("drafts.**"))]
🙂
Mar 29, 2020, 3:07 PM
R
P.S. If you want to query both the draft and the non-draft
_idin the query above, you could try something like this:
*[_type == "category"] { name, "allBlogPosts": *[_type == "blogPost" && ^._id match category._ref] { title, } }
Mar 29, 2020, 3:19 PM
R
Thanks
On an artist-page I query some data from the artist document like so
, but also all artworks that have a reference to the artist. like . Now when I want to preview a draft of an artist-page like the query for the artworks refers to the draft
So what I think I’m looking for is a way to have
user M
! I’m not sure about Marco’s case, but in my situation I have an artist document and artwork objects. Artwork objects have a reference to an artist.On an artist-page I query some data from the artist document like so
*[_type == 'artist' && slug.current == $slug][0]
*[_type == "artwork" && references(^._id)]
*[_type == 'artist' && slug.current == $slug && _id in path('drafts.**')][0]
_idand subsequently no artworks show up they are connected to the to the public version of the artist, and not the draft version.
So what I think I’m looking for is a way to have
^._idbut remove the
drafts.-prefix with some kind of string manipulation. Hope that’s clear!
Mar 29, 2020, 9:03 PM
D
Hi Bauke, thanks for explaining! I think I’m with you now. I’m not sure what your artist reference field in
artworkis called, but let’s say it’s called
artistfor this example. Then could you try replacing the artwork query by something like this?
*[_type == "artwork" && ^.id match artist._ref]
Mar 29, 2020, 9:57 PM
R
Thanks, I tried your solution, but I’m afraid it didn’t work. The artist reference is indeed called
If it helps, here is the complete original query and the query with your solution:
If I’m not mistaken, the
artistbut I think the problem is the same: the
^.idin that solution still points to the draft-id while the artwork expects the non-draft-id.
If it helps, here is the complete original query and the query with your solution:
*[_type == 'artist' && slug.current == $slug && _id in path('drafts.**')][0] { _id, someOtherStuff, "artworks": *[_type == "artwork"&& references(^._id)] { _id, someOtherStuff, } }
*[_type == 'artist' && slug.current == $slug && _id in path('drafts.**')][0] { _id, someOtherStuff, "artworks": *[_type == "artwork" && ^.id match artist._ref] { _id, someOtherStuff, } }
^.idin the above queries refer to the same.
Mar 30, 2020, 7:37 AM
D
Indeed, they do refer to the same draft
_idbut
matchshould let you find a match between the draft and non-draft ids, or so I thought anyway 😉 Could you try it the other way around just for fun?
... && artist._ref match ^.idIf it doesn’t work, I’ll have a closer look at this.
Mar 30, 2020, 7:56 AM
R
Alright, I’ll give that a try!
Mar 30, 2020, 7:58 AM
R
Both ways round give an Internal server error.
Mar 30, 2020, 8:01 AM
P
Hmm, that shouldn’t happen though. Do you have any repo by any chance that you could share a link to in DM? I’m happy to try and get this working for you.
Mar 30, 2020, 8:02 AM
R
I think my use case is quite similar. On non-production links, for each document I always pick the draft version (if there is one) over the published document.
In my case, each
In the website, there is a page for each category showing all of the blog posts that belong to that category.
My issue comes up when the category is the draft (and not the published version). How can I select all of the
Hope the explanation is clear, thank you!
In my case, each
blogPostdocument holds a reference to
categorydocument (e.g. this blog post is in the "Travel" category).
In the website, there is a page for each category showing all of the blog posts that belong to that category.
My issue comes up when the category is the draft (and not the published version). How can I select all of the
blogPostdocuments that referenced the published version of the current category draft?
Hope the explanation is clear, thank you!
Mar 30, 2020, 8:53 AM
R
user M
I tried the query that you suggested:*[_type == "category"] { name, "allBlogPosts": *[_type == "blogPost" && ^._id match category._ref] { title, } }
Mar 30, 2020, 9:08 AM
D
Hi both, I was just able to reproduce the Internal Server Error that you’re both getting. Seems like the query works when you replace
There are workarounds though, like the one Marco already kind of suggested in the original post — but with the $slug variable that Bauke has in his implementation as it won’t work with
Now let’s figure out a way to fix this for Marco too without needing a separate query for the slug
😉
^._idwith an actual draft id string but not as an enclosed record reference. I’ll share that with the team because it seems strange.
There are workarounds though, like the one Marco already kind of suggested in the original post — but with the $slug variable that Bauke has in his implementation as it won’t work with
^.slug.currentfor some reason:
*[_type == 'artist' && slug.current == $slug][0] { _id, someOtherStuff, "artworks": *[_type == "artwork" && artist->slug.current == $slug] { _id, someOtherStuff } }
😉
Mar 30, 2020, 6:06 PM
D
Did some more testing. I think this is a more solid solution to the issue:
The
This should work in Marco’s case as well:
*[_type == 'artist' && slug.current == $slug] | order(_updatedAt desc)[0] { _id, someOtherStuff, "artworks": *[_type == "artwork" && (artist._ref == ^._id || 'drafts.' + artist._ref == ^._id)] { _id, someOtherStuff } }
orderis specified to ensure it picks the most recently updated artist document for the current slug. Afterwards it checks for the
artist._refwith and without a
'drafts.'string in front of it to find a match. I couldn’t find an easy way to slice
drafts.off the
^._idso I added it to the
_refinstead. Can’t beat ’em, join ‘em 🤷♂️
This should work in Marco’s case as well:
*[_type == "category"] { name, "allBlogPosts": *[_type == "blogPost" && (category._ref == ^._id || 'drafts.' + category._ref == ^._id)] { title, } }
Mar 30, 2020, 6:33 PM
R
Hey Peter, I just tried the query that you suggested and it worked! I didn't know I could do string concatenation like that in a GROQ query.
Thank you so much again for looking into this — hopefully we helped finding some edge case-related bug that will improve Sanity overall!
Thank you so much again for looking into this — hopefully we helped finding some edge case-related bug that will improve Sanity overall!
Mar 30, 2020, 7:33 PM
R
To be honest, I didn’t know either until I tried today 😄 I think you might not need the parentheses and even
Thanks both for reporting this and insisting to have it looked at! We won’t find all these edge cases without you
✨
_type == "blogPost"in the
allBlogPostsquery but it doesn’t harm to keep them.
Thanks both for reporting this and insisting to have it looked at! We won’t find all these edge cases without you
✨
Mar 30, 2020, 7:40 PM
Sanity– build remarkable experiences at scale
Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.