go - Datastore: Create parent and child entity in an entity group transaction? -


after reading google datastore concepts/theory started using go datastore package

scenario: kinds user , linkedaccount require every user has 1 or more linked accounts (yay 3rd party login). strong consistency, linkedaccounts children of associated user. new user creation involves creating both user , linkedaccount, never one.

user creation seems perfect use case transactions. if, linkedaccount creation fails, transaction rolls fails. doesn't seem possible. goal create parent , child within transaction.

according docs

all datastore operations in transaction must operate on entities in same entity group if transaction single group transaction

we want new user , linkedaccount in same group, me sounds datastore should support scenario. fear intended meaning operations on existing entities in same group can performed in single transaction.

tx, err := datastore.newtransaction(ctx) if err != nil {     return err } incompleteuserkey := datastore.newincompletekey(ctx, "user", nil) pendingkey, err := tx.put(incompleteuserkey, user) if err != nil {     return err } incompletelinkedaccountkey := datastore.newincompletekey(ctx, "githubaccount", incompleteuserkey) // tried pendingkey parent, separate struct type _, err = tx.put(incompletelinkedaccountkey, linkedaccount) if err != nil {     return err } // attempt commit if _, err := tx.commit(); err != nil {     return err } return nil 

from library source clear why doesn't work. pendingkey's aren't keys , incomplete keys can't used parents.

is necessary limitation of datastore or of library? experienced type of requirement, did sacrifice strong consistency , make both kinds global?

for google-ability:

  • datastore: invalid key
  • datastore: cannot use pendingkey type *"google.golang.org/cloud/datastore".key

one thing note transactions in cloud datastore api can operate on 25 entity groups, doesn't answer question of how create 2 entities in same entity group part of single transaction.

there few ways approach (note applies use of cloud datastore api, not gcloud-golang library):

  1. use (string) name parent key instead of having datastore automatically assign numeric id:

    parentkey := datastore.newkey(ctx, "parent", "parent-name", 0, nil) childkey := datastore.newincompletekey(ctx, "child", parentkey) 
  2. make explicit call allocateids have datastore pick numeric id parent key:

    incompletekeys := [1]*datastore.key{datastore.newincompletekey(ctx, "parent", nil)} completekeys, err := datastore.allocateids(ctx, incompletekeys) if err != nil {   // ... } parentkey := completekeys[0] childkey := datastore.newincompletekey(ctx, "child", parentkey) 

Comments