Getting user data in a Sanity query and using a person document type for authors

10 replies
Last updated: Dec 2, 2020
Can I somehow get which user has created the document from a query?
AI Update

Unfortunately, Sanity doesn't provide built-in system fields for tracking which user created or modified a document. The system fields available on documents are:

  • _id - Unique identifier
  • _type - Document type
  • _rev - Revision tracking
  • _createdAt - Timestamp when created
  • _updatedAt - Timestamp when last modified

Notice there's no _createdBy or _updatedBy field that you can query.

Workarounds

If you need to track document creators, you have a couple of options:

1. Manual author field in your schema

Add an author/creator field to your document schema that references a user document:

defineField({
  name: 'author',
  type: 'reference',
  to: [{type: 'person'}]
})

You'd need to manually create person documents for each Sanity user and set this field when creating content.

2. Use Initial Value Templates

You can use Initial Value Templates to automatically populate the author field when a document is created, though this still requires manual setup.

3. Use the History API for audit trails

While you can't query it directly in GROQ, the History API does track transaction history including user information. This is useful for audit trails but not for querying documents by creator in your content queries.

There's a community discussion with a script example for creating person documents from Sanity users if you want to automate the initial setup.

The lack of built-in creator tracking is a common limitation in headless CMS systems where the content authoring layer is separated from the content data layer.

Yes, you can use below code for the reference through which you can get email id (User object) & you can do whatever stuff you would like to do with it.
import userStore from 'part:@sanity/base/user'
// remember to add rxjs/operators to your dependencies with npm or yarn
import {
  map
} from 'rxjs/operators'

export default () => userStore.currentUser.pipe(
  map(({user}) => {
    const {email} = user

    console.log("Email:", email);
  })
)
I was thinking if I can have that for each document when I'm calling the api on the front-end
Okay! So, you are going to use that on front-end. You can add hidden input field or something else in document form & then you can store the user in it with custom publish action or something else. Then, you will get that entire user object on front-end with respect to particular document that you are trying to fetch
You have to add the value of last edited by user in that hidden input field
Okay, will try that. It would've be nice though if we had that data available in the result from the query. Thanks.
Usually people make a
person
 document type and an
authors
 field as an array of references to
person
(or just a reference field if you know it's always restricted to one author). That way your content isn't tied to user accounts that forces you to keep users and so on even if they leave the project. Check out the content models for our blogs starters and so for how to set that up.
You can add a userId field on a person document to e.g. create some logic to have the author field automatically be populated by the current logged in user
I tried that, but in the result of the query I don't see the author field, any idea why?
I mean, actually defining schemas like this:
https://github.com/sanity-io/sanity-template-gatsby-blog/blob/master/template/studio/schemas/documents/post.js#L42-L51
https://github.com/sanity-io/sanity-template-gatsby-blog/blob/master/template/studio/schemas/objects/authorReference.js
https://github.com/sanity-io/sanity-template-gatsby-blog/blob/master/template/studio/schemas/documents/author.js (just add an
id
or
email
 field to the schema as well)and then you can use initial values to match the current user to a field in the
author
 (or
person
) document:
import client from 'part:@sanity/base/client'
import userStore from 'part:@sanity/base/user'

const getAuthorId = async () => {
  const {id = '', email = '', name = ''} = await userStore.getUser('me')
  const _id = await client.fetch(`*[
    _type == "author" && (
      sanityID == $id ||
      email == $email ||
      name match $name
    )
  ][0]._id`, {id, email, name}).catch(error => console.error(error) || null)
  return _id
}
export default  {
  title: 'Post',
  name: 'post',
  type: 'document',
  initialValue: async () => {
    const authorId = await getAuthorId()
    if (!authorId) {
      return {}
    }
    return {
      authors: [
        {
          _type: 'reference',
          _ref: authorId
        }
      ]
    }
  },
  fields: [ /* the post fields */]
}

Okay, I already have person document but for some of the editors there will not be any data in that entity, and since I only need the email (to send notification for successfully created promotion campaign in AWS Pinpoint) I just need to somehow attach that to the document. Don't want to get too much into how it is implemented 'cos don't see a point why that would metter, I just need the email of the person that has created the document and why the custom input field doesn't take the initial value?

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?