Repository navigation
Can't save and delete in a transaction #1339
Copy link
Copy link
Closed
Labels
api: datastoreIssues related to the Datastore API.Issues related to the Datastore API.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Description
Activity
@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? falseAnd 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 } } } } ] }- addedapi: datastoreIssues related to the Datastore API.Issues related to the Datastore API.
on May 25, 2016 @stephenplusplus That seems odd. One thing to double check, is that the full commit message? Because I don't see any transaction specified there.
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==" }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.
Ah, okay, so just confirming, it should be:
mutations = [ { delete: {} }, { upsert: {} }, { delete: {} }, { upsert: {} } ]
- addedtype: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
on May 25, 2016 PR sent with a fix: #1341
Released in 0.35.0.
Reacted by susanlinsfu- added a commit that references this issue
on Jul 23, 2025 - added a commit that references this issue
on Feb 3, 2026 - added a commit that references this issue
on Mar 11, 2026 - added a commit that references this issue
on Mar 18, 2026
Metadata
Metadata
Assignees
Labels
api: datastoreIssues related to the Datastore API.Issues related to the Datastore API.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
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).
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!