Using `walkjs` to fetch and attach image metadata in Sanity queries
6 replies
Last updated: Jun 7, 2024
L
Is there an easy way to get the blurhash from the image metadata without having to do anything in groq?
Ideally I'd like it to just always pull down so I don't have to edit every query
Ideally I'd like it to just always pull down so I don't have to edit every query
Jun 6, 2024, 4:56 PM
N
Hey User! Yes, in the query every time but my team has in the past used utilities that use
walkjsto traverse the returned data, grab the image refs and re-query the extra metadata, and reattach them to the data to avoid super long queries, highly recommend these!
Jun 6, 2024, 7:47 PM
I
user D
Do you have a code example?Jun 7, 2024, 8:31 AM
N
import { WalkBuilder, deepCopy } from "walkjs" export const resolveLinks = async (inputData, maxDepth = 5) => { const store = new Map() const replaceNode = (node, id) => { const doc = store.get(id) if (["link"].includes(node.key)) { const values = { slug: doc._type === "home" ? { _type: "slug", current: "/" } : { _type: "slug", current: "/" + (doc.slug?.current ? doc.slug.fullUrl || doc.slug.current : `${doc._type}`), }, label: node.parent?.val?.label, docType: doc._type, } const _key = node.val._key || node.parent.val._key || doc._key if (_key) { values._key = _key } Object.keys(node.parent.val).forEach(key => delete node.parent.val[key]) Object.keys(values).forEach(key => { node.parent.val[key] = values[key] }) } else { Object.keys(node.val).forEach(key => delete node.val[key]) Object.keys(doc).forEach(key => { const value = doc[key] node.val[key] = typeof value === "object" ? deepCopy(value) : value }) } } const iterate = async nodes => { const ids = new Map() new WalkBuilder() .withGlobalFilter(a => a.val && a.val._type === "reference") .withSimpleCallback(node => { const refId = node.val._ref if (typeof refId !== "string") { throw new TypeError("node.val is not set") } if (!refId.startsWith("image-")) { if (!store.has(refId)) { // unresolved, add it to the list ids.set(refId, node) } else { // already resolved, can be replaced immediately replaceNode(node, refId) } } }) .walk(nodes) if (ids.size) { // fetch all references at once const documents = await sanityClient.fetch( `*[_id in [${[...ids.keys()].map(id => `'${id}'`).join(",")}]]{...}` ) documents.forEach(element => { store.set(element._id, element) }) // replace them ids.forEach((node, id) => { replaceNode(node, id) }) if (!--maxDepth) { console.error("Sanity autoresolver max depth reached") return } // iterate threw newly fetched nodes await iterate(nodes) } } await iterate(inputData) }
Jun 7, 2024, 8:32 AM
I
Awesome, thanks 🙏
Jun 7, 2024, 8:33 AM
N
To break it down:
1. Go thru the response of a query, find anything with _ref
2. Add to a list
3. Query eveything on the list
4. Attach returned reference data to object
1. Go thru the response of a query, find anything with _ref
2. Add to a list
3. Query eveything on the list
4. Attach returned reference data to object
Jun 7, 2024, 8:33 AM
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.