Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't save and delete in a transaction #1339

Closed
susanlinsfu opened this issue May 24, 2016 · 7 comments
Closed

Can't save and delete in a transaction #1339

susanlinsfu opened this issue May 24, 2016 · 7 comments
Assignees
Labels
api: datastore Issues related to the Datastore API. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.

Comments

@susanlinsfu
Copy link

susanlinsfu commented May 24, 2016

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!

@stephenplusplus
Copy link
Contributor

stephenplusplus commented May 25, 2016

@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
          }
        }
      }
    }
  ]
}

@stephenplusplus stephenplusplus added the api: datastore Issues related to the Datastore API. label May 25, 2016
@pcostell
Copy link
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.

@stephenplusplus
Copy link
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=="
}

@pcostell
Copy link
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.

@stephenplusplus
Copy link
Contributor

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

mutations = [
  { delete: {} },
  { upsert: {} },
  { delete: {} },
  { upsert: {} }
]

@stephenplusplus stephenplusplus added the type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns. label May 25, 2016
@stephenplusplus
Copy link
Contributor

PR sent with a fix: #1341

@stephenplusplus
Copy link
Contributor

Released in 0.35.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: datastore Issues related to the Datastore API. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Projects
None yet
Development

No branches or pull requests

4 participants