T9b
T9b

Reputation: 3502

Is it possible to do transaction processing using node.js and a noSQL db?

I'm not talking about real money transactions

The project I'm working on is a game where players trade stuff between each other. It's basically a transaction process, player A gives player B 10 groats in exchange for thirty cows, you get the idea.

But as it's interactive and there are many players at once, in a chatroom-like environment all trading randomly I wondered if it was possible to do such a thing with node.js but I see problems.

I come from a DB background where processing transactions and the nature of rollback and commit are necessary to maintain the DB state of health. But if we're talking node.js plus mongoDB (or any other noSQL DB for that matter) that surely is a whole different mentality, but I just don't see how it could handle a trade in the sense that only two parties should be involved without resorting to some form of locking, but surely that's not what node is about.

I haven't found anything yet, but that does not surprise me because node.js is so new.

UPDATE I am aware of the mechanisms of a transaction - and in particular banking style transactions, but this is not the same thing. I may not have made it clear, but the issue is that player B is selling something, to a community of buyers.

That means that although player A initiates a buy instruction on the client side it is also possible that around the same time Player C D or E also clicks to buy the same Cow.

Now in a normal transaction it is expected that at least the first person who obtains a record level table lock at least blocks the other parties from proceeding at that point in time.

However the nature of use of node and in particular its speed, concurrent processing and use for displaying real-time updates database mean that I could easily imagine that the slowest person (we're talking milliseconds) wins.

For example Player A initiates the purchase at the same time as player C. Player A transaction completes and the Groats are paid to Player B, and the Cow is assigned to Player A on the database. A millisecond later the Cow is assigned to player C.

I hope that explains the issue better.

Upvotes: 5

Views: 16803

Answers (3)

mikermcneil
mikermcneil

Reputation: 11271

I'm working on an oss application-level transaction database for node.js called Waterline.

We started with full-on CRUD mutices, but soon realized that was pretty hard. Better to leave that to the database. But sometimes you don't want to-- because you want to be able to switch databases and keep your code agnostic. So then we simplified down to the next easiest piece-- named transactions.

So, no rollback support built in (you'll still have to do that yourself for now), but at least Waterline prevents concurrent access for you.

In your example (assuming you're in express/connect/Sails) it might look something like:

function buyCow (req,res) {
   Cow.find(req.param('cowId'),function (err,cow) {
      if (err) return req.send(500,err);

      Cow.transaction('buy_cow',function (err, unlock) {
         if (err) { 
            // Notice how I unlock before each exit point?  REALLY important.
            // (would love to hear thoughts on an easier way to do this)
            unlock(); 
            return res.send(500,err); 
         }

         User.find(req.session.userId,function (err,user) {
            // If there's not enough cash, send an error
            if (user.money - cow.price < 0) { 
               unlock();
               return res.send(500,'Not enough cash!');
            }

            // Update the user's bank account
            User.update(user.id,{
               money: user.money - cow.price
            }, function (err,user) {
               if (err) { unlock(); return res.send(500,err); }

               Cow.update(cow.id, {owner: user.id}, function (err, cow) {
                  if (err) { unlock(); return res.send(500,err); }

                  // Success!
                  unlock();
                  res.json({success: true});
               });

            });
         });
      });

   });
}

Hope that helps. I welcome your feedback (and maybe commits?)

Upvotes: 2

J Chris A
J Chris A

Reputation: 2168

To do banking style transactions with a document database, it is typical to use a transaction log pattern. In this pattern you'd write each transaction as it's own document. You do not maintain documents corresponding to each account balance. Instead, you roll the transaction documents up at query time, to give the current balance(s).

Here is an example that is applicable to Couchbase map reduce: http://guide.couchdb.org/draft/recipes.html

Upvotes: 2

freakish
freakish

Reputation: 56467

This has nothing to do with Node.JS. Node.JS only connects to the database and transactions are done by database itself (unless you want to manually implement transactions in Node.JS, which might be a bit difficult task - but that's the same for any web server written in any language).

You can easily use (for example) MySQL with Node.JS which supports transactions. So the question you are asking is: can I do transactions with MongoDB? The answer is: no and yes.

No, because MongoDB does not support transactions out of the box.

Yes, because you can use some tricks to emulate transactions. See for example this article.

Upvotes: 4

Related Questions