Questions about fields that are unique based on parent and child entities

Hello! I am looking into DGraph for a database for animation or VFX studios. I have a couple questions that may be related, but I’m not 100% sure how to do.

Assuming the types…

type Sequence {
    name: string
    takes: [Take!]
    shots: [Shot!]
}

type Shot {
    name: string
    takes: [Take!]
}

union TakeParent = Shot | Sequence

type Take {
    parent: TakeParent!
    version: int!
}

Question 1

I want it so that any Take associated to a Shot is uniquely versioned. For example, if there is Shot010 and Shot020, and each of those have 3 versions each, and if I run a query like:

query {
    q(func: type("Shot")) {
        name
        takes {
            version
        }
    }
}

I want a result like this:

[
    {
        "name": "Shot010",
        "takes": [
            {
                "version": 1
            },
            {
                "version": 2
            },
            {
                "version": 3
            }
        ]
    },
    {
        "name": "Shot020",
        "takes": [
            {
                "version": 1
            },
            {
                "version": 2
            },
            {
                "version": 3
            }
        ]
    }
]

I tried wrapping my head around upserts, but I think I’m not implementing it right. I tried something like this:

upsert {
    query {
        q(func: uid("0x8")) {
            e as uid
            takes {
                t as val(func: max(version)) {
                    v as version
                }
            }
        }
    }

    mutation {
        set {
            uid(t) <dgraph.type> "Take" .
            uid(t) <parent> uid(e) .
            uid(t) <version> val(v) .
        }
    }
}

But it looks like my syntax is off. So, my question is I guess two parts. How do I do this in DQL, and how (if possible) can I do this in GraphQL while making the version increment strictly unique for each take per shot?

Question 2

Similar to question 1, but I want each shot to be unique for each sequence. So, if I have a list of sequences like this:

[
    {
        "name": "Sequence010",
        "shots": [
            {
                "name": "Shot010"
            },
            {
                "name": "Shot020"
            }
        ]
    },
    {
        "name": "Sequence020",
        "shots": [
            {
                "name": "Shot010"
            },
            {
                "name": "Shot020"
            }
        ]
    }
]

And I tried to add a shot called Shot010 to either sequence, then how can I make the database throw an error and rollback the change?

Thanks for your help!

cc: @MichelDiz

So, no shot has more than 3 versions? Do You wanna increment until reach 3 versions? is that your constraint?

The “func” notation can be used only at root. Never in nested blocks. Also, max aggregation won’t work as a method.

To do increment I would do this

upsert {
    query {
      e as q(func: eq(name, "Shot030")) {
        takes {
            V as version
          }
        }
        me(){
          MX2 as max(val(V))
          inc as math(1+MX2)
        }
    }

    mutation {
        set {
            _:AlwaysNew  <dgraph.type>  "Take" .
              uid(e)     <takes>   _:AlwaysNew .
            _:AlwaysNew  <version>  val(inc)   .
        }
    }
}

Dataset

{
   "set": [
      {
         "name": "Shot030",
         "takes": [
            {
               "version": 1
            },{
               "version": 2
            }
         ]
      }
   ]
}

It won’t “rollback” but using Upsert you can avoid someone introducing duplicates.

BTW, instead, of using the “Name” predicate as a referenceable value. I would use numbers instead. And use the “Name” predicate for a custom human friendly value. Like “I will call the shot 010 something something” and it still will have the number stating what shot it is.

e.g:

{
   "set": [
      {
         "name": "Candidate 1",
         "description": "The Candidate gets into the secret room and discovers the whole thing related to his past.",
         "shot": "030",
         "takes": [
            {
               "version": 1
            },{
               "version": 2
            }
         ]
      }
   ]
}

Thanks for the reply!

The 3 versions are arbitrary, but the versions can be anything from 1 to infinity. The constraint is each version must be unique for each parent entity (Takes that are child of shot 010, for example must all be unique, but there may be two takes that are version 1 if the parent shots are different).

Thanks, I’ll try this!

Hmm. So, let me make sure that I understand what you said with the following scenario.

We’ve connected our db with another db (such as connecting to a project management service called Shotgun or FTrack). We’ve set strict rules in our db such that each shot name must be unique per sequence. Shotgun and FTrack may not have that constraint, so someone in production goes in and accidentally makes two shot 010 for sequence 010 which gets synced down to our db. Is there a way in db (I’m assuming with upsert) to check if the shot name already exists, and if it does, throw an error?

That makes sense, but if a client requires the shot naming to be a certain way, then we’d probably want to support it. For example, if there are insert shots, they may be called 010a, 010b or 010.01. Also, if there’s RND shots, then you may want to name the shot test_falling_down. But, there usually is an order value to handle sorting the shots (usually optional).

Thank you very much for getting back to me!