Sorting content by date in Sanity with a custom script
10 replies
Last updated: May 6, 2022
T
Hey Sanity Land 👋
I'm having a hard time wrapping my head around ordering content based on dateTimes. Is there a way to remove time from
I need to be able to sort by multiple fields while having posts maintain chronological order.
The only way I can think about having this work is by adding another field to our schema that is
Thoughts?
I'm having a hard time wrapping my head around ordering content based on dateTimes. Is there a way to remove time from
dateTimefields in Sanity?
I need to be able to sort by multiple fields while having posts maintain chronological order.
The only way I can think about having this work is by adding another field to our schema that is
dateand run a script to add data to these to the existing 3000+ document dataset.
Thoughts?
May 6, 2022, 6:26 PM
Hi User. I think you’re right. Without a substring or slice function I don’t believe you can currently do this solely in GROQ.
May 6, 2022, 6:45 PM
T
user A
Is there a substring or slice function that's undocumented? 👀May 6, 2022, 6:46 PM
T
Any other creative solutions that you are aware of? I can't imagine that this is an uncommon use case or need.
May 6, 2022, 6:47 PM
All I can think of are either a document action to store a date on your document based on the dateTime field, like you suggested, or doing the sort outside of GROQ after you’ve fetched.
May 6, 2022, 6:50 PM
T
Thanks User. Document action is a good call, unfortunately won't work in our case but a great suggestion.
Thank you for the internal ticket. Much appreciated.
Thank you for the internal ticket. Much appreciated.
May 6, 2022, 6:56 PM
T
user A
While we're on the topic, what's the most simple way to backfill the data needed?May 6, 2022, 8:55 PM
I might start with something like this, though I would urge testing on a non-production dataset first to make sure it works as expected.
You’d put the following somewhere in your studio folder and run it with
, first changing out
You’d put the following somewhere in your studio folder and run it with
sanity exec path/to/script.js --with-user-token
NEW_DATE_FIELDand `DATETIME_FIELD`:
import sanityClient from 'part:@sanity/base/client' const client = sanityClient.withConfig({ apiVersion: '2022-05-06' }) const fetchDocuments = () => client.fetch(`*[DATETIME_FIELD != null && NEW_DATE_FIELD == null][0...100] {_id, _rev, DATETIME_FIELD, NEW_DATE_FIELD}`) const buildPatches = docs => docs.map(doc => ({ id: doc._id, patch: { set: {NEW_DATE_FIELD: doc.DATETIME_FIELD.slice(0, 10)}, // this will cause the migration to fail if any of the documents has been // modified since it was fetched. ifRevisionID: doc._rev } })) const createTransaction = patches => patches.reduce((tx, patch) => tx.patch(patch.id, patch.patch), client.transaction()) const commitTransaction = tx => tx.commit() const migrateNextBatch = async () => { const documents = await fetchDocuments() const patches = buildPatches(documents) if (patches.length === 0) { console.log('No more documents to migrate!') return null } console.log( `Migrating batch:\n %s`, patches.map(patch => `${patch.id} => ${JSON.stringify(patch.patch)}`).join('\n') ) const transaction = createTransaction(patches) await commitTransaction(transaction) return migrateNextBatch() } migrateNextBatch().catch(err => { console.error(err) process.exit(1) })
May 6, 2022, 10:26 PM
This will find all the documents where your
DATETIME_FIELDexists and
NEW_DATE_FIELDdoes not (if you exclude the second one, this would keep running forever). It then sets
NEW_DATE_FIELDto be the first 10 characters of your
DATETIME_FIELD, which is the date as
YYYY-MM-DD. Finally, it bundles those up as packages of 100 so you don’t rate limit yourself.
May 6, 2022, 10:28 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.