Skip to content

Can't save and delete in a transaction #1339

Description

@susanlinsfu

I asked this question on stackoverflow, but am also posting here as an issue (http://stackoverflow.com/questions/37401751/cant-save-and-delete-in-a-transaction).

var cachedTransaction;
datastore.runInTransaction(function(transaction, done) {
            cachedTransaction = transaction;

            var keys = [
                datastore.key([PARENT_TABLE, p1]),
                datastore.key([PARENT_TABLE, p2]),
                datastore.key([PARENT_TABLE, p1, CHILD_TABLE, p2])
            ];

            transaction.get(keys, function(err, entities) {

                    if (err) {
                        transaction.rollback();
                    }

                    if (entities) {
                        transaction.save([{
                            key: datastore.key([PARENT_TABLE, p1]),
                            method: 'update',
                            data: {
                                p: 100
                            }
                        }, {
                            key: datastore.key([config.PARENT_TABLE, p2]),
                            method: 'update',
                            data: {
                                p: 100
                            }
                        }]);

                        transaction.delete([

                            datastore.key([PARENT_TABLE, p1, CHILD_TABLE, p2]),
                            datastore.key([PARENT_TABLE, p2, CHILD_TABLE, p1])

                        ]);

                    } else {
                        console.log('Entities are empty');
                    }
                    console.log('commiting ... ');
                    done();
                    console.log('commited ');

                } else {
                    transaction.rollback();
                }
            });

    },
    function(err) {
        console.log('commited complete. Was it successful ? ');
        if (err) {
            console.log('err : ' + err);
            cachedTransaction.rollback();
        }
    });

With the following code I am getting two entities from a parent table and one entity from a child table (I print some stuff with this child entity not shown in code). I then update the two parent entities and delete two child entities (one which I did not get get from my original response). The result is that the parent entities do get updated, but the two children entities do NOT get deleted. I get no error messages.

If I comment out the save portion of the code which updated the parents, then it will delete the child entities, but I need to update the parent and delete the children. How can I do this? I am using gcloud-node 0.34.0 and running off the actual Google Cloud Datastore.

Thanks!

Activity

  1. stephenplusplus commented on May 25, 2016

    @stephenplusplus
    Contributor

    @pcostell could you give this one a quick look to make sure things look correct?

    Here's the script I've tested with:

    'use strict';
    
    var gcloud = require('gcloud');
    var datastore = gcloud.datastore();
    
    var PARENT_TABLE = 'Parent';
    var CHILD_TABLE = 'Child';
    
    var p1 = 'pname1';
    var p2 = 'pname2';
    
    insertInitialData(runTransaction);
    
    function insertInitialData(callback) {
      datastore.save([
        {
          key: datastore.key([PARENT_TABLE, p1]),
          data: {
            p: 0
          }
        },
        {
          key: datastore.key([PARENT_TABLE, p2]),
          data: {
            p: 0
          }
        },
        {
          key: datastore.key([PARENT_TABLE, p1, CHILD_TABLE, p2]),
          data: {
            p: 0
          }
        },
        {
          key: datastore.key([PARENT_TABLE, p2, CHILD_TABLE, p1]),
          data: {
            p: 0
          }
        }
      ], callback);
    }
    
    function runTransaction() {
      var keysToGet = [
        datastore.key([PARENT_TABLE, p1]),
        datastore.key([PARENT_TABLE, p2]),
        datastore.key([PARENT_TABLE, p1, CHILD_TABLE, p2])
      ];
    
      var keysToDelete = [
        keysToGet[2],
        datastore.key([PARENT_TABLE, p2, CHILD_TABLE, p1])
      ];
    
      var keysToUpdate = [
        datastore.key([PARENT_TABLE, p1]),
        datastore.key([PARENT_TABLE, p2])
      ];
    
      datastore.runInTransaction(function(transaction, done) {
        transaction.get(keysToGet, function(err, entities) {
          if (err) {
            transaction.rollback();
            done();
            return;
          }
    
          if (entities.length === 0) {
            console.log('Entities are empty');
            done();
            return;
          }
    
          transaction.save([{
            key: keysToUpdate[0],
            method: 'update',
            data: {
              p: 100
            }
          }, {
            key: keysToUpdate[1],
            method: 'update',
            data: {
              p: 100
            }
          }]);
    
          transaction.delete(keysToDelete);
    
          done();
        });
      }, function(err) {
        if (err) {
          throw err;
        }
    
        datastore.get(keysToUpdate, function(err, entities) {
          if (err) {
            throw err;
          }
    
          console.log('Updated entities?', entities.every(function(entity) {
            return entity.data.p === 100;
          }));
    
          datastore.get(keysToDelete, function(err, entities) {
            if (err) {
              throw err;
            }
    
            console.log('Deleted entities?', entities.length === 0);
          });
        });
      });
    }

    Running returns:

    Updated entities? true
    Deleted entities? false
    

    And the commit request that gets sent when done() (commit) is called.

    {
      "mutations": [
        {
          "delete": {
            "path": [
              {
                "kind": "Parent",
                "name": "pname1"
              },
              {
                "kind": "Child",
                "name": "pname2"
              }
            ]
          },
          "update": {
            "key": {
              "path": [
                {
                  "kind": "Parent",
                  "name": "pname1"
                }
              ]
            },
            "properties": {
              "p": {
                "integerValue": 100
              }
            }
          }
        },
        {
          "delete": {
            "path": [
              {
                "kind": "Parent",
                "name": "pname2"
              },
              {
                "kind": "Child",
                "name": "pname1"
              }
            ]
          },
          "update": {
            "key": {
              "path": [
                {
                  "kind": "Parent",
                  "name": "pname2"
                }
              ]
            },
            "properties": {
              "p": {
                "integerValue": 100
              }
            }
          }
        }
      ]
    }
  2. pcostell commented on May 25, 2016

    @pcostell
    Contributor

    @stephenplusplus That seems odd. One thing to double check, is that the full commit message? Because I don't see any transaction specified there.

  3. stephenplusplus commented on May 25, 2016

    @stephenplusplus
    Contributor

    Yes, that was just the mutations part, sorry. The full thing is here:

    {
      "mutations": [
        {
          "delete": {
            "path": [
              {
                "kind": "Parent",
                "name": "pname1"
              },
              {
                "kind": "Child",
                "name": "pname2"
              }
            ]
          },
          "update": {
            "key": {
              "path": [
                {
                  "kind": "Parent",
                  "name": "pname1"
                }
              ]
            },
            "properties": {
              "p": {
                "integerValue": 100
              }
            }
          }
        },
        {
          "delete": {
            "path": [
              {
                "kind": "Parent",
                "name": "pname2"
              },
              {
                "kind": "Child",
                "name": "pname1"
              }
            ]
          },
          "update": {
            "key": {
              "path": [
                {
                  "kind": "Parent",
                  "name": "pname2"
                }
              ]
            },
            "properties": {
              "p": {
                "integerValue": 100
              }
            }
          }
        }
      ],
      "projectId": "nth-circlet-705",
      "mode": "TRANSACTIONAL",
      "transaction": "EQA6Wuslj8Q/IlkAM9qycvuHuvP30Lxax8rLQToFhMqIJzOwWishYI7n2zQxHpmybeKYoNjQ8zjTA/7s8eXQizRmcLQJr/R1wURemBZpMlg5FzSMTAXQ7JxwU+1/PI96X/C0eg=="
    }
  4. pcostell commented on May 25, 2016

    @pcostell
    Contributor

    Ah it looks like your mutations are being created incorrectly. In particular, you only have two mutations, each one with an upsert and a delete.

    The way proto oneof fields work, it will only ever accept the last one set.

  5. stephenplusplus commented on May 25, 2016

    @stephenplusplus
    Contributor

    Ah, okay, so just confirming, it should be:

    mutations = [
      { delete: {} },
      { upsert: {} },
      { delete: {} },
      { upsert: {} }
    ]
  6. added
    type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.
    on May 25, 2016
  7. stephenplusplus commented on May 25, 2016

    @stephenplusplus
    Contributor

    PR sent with a fix: #1341

  8. stephenplusplus commented on Jun 2, 2016

    @stephenplusplus
    Contributor

    Released in 0.35.0.

  9. added a commit that references this issue on Jul 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

api: datastoreIssues related to the Datastore API.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions