Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the synchronous/asynchronous properties of the mongo shell?

I'm used to JavaScript being non-blocking/async, especially when it comes to IO. That's why the mongo shell kind of weirds me out. Take this example from MongoDb: The Definitive Guide:

(from page 31):


For example, suppose we insert a million dummy elements with the following:

> for (var i = 0; i < 1000000; i++) {
... db.tester.insert({"foo": "bar", "baz": i, "z": 10 - i}) ... }

Now we’ll try to remove all of the documents we just inserted, measuring the time it takes. First, here’s a simple remove:

> var timeRemoves = function() {
... var start = (new Date()).getTime();
...
... db.tester.remove();
... db.findOne(); // makes sure the remove finishes before continuing ...
... var timeDiff = (new Date()).getTime() - start;
... print("Remove took: "+timeDiff+"ms");
... }
> timeRemoves()

See that comment by db.findOne()? That's straight from the text. Bumping streams like that isn't totally weird to me, but it's the kind of thing that you don't know about until you spend a long time trying to figure out what's wrong with something you expect to work.

So, what is the async/sync deal with the mongo shell? How am I supposed to know what to expect, and when and how to bump IO ops like the one above. Is this documented anywhere? Is there any way to get it to work asynchronously, like JS normally behaves? I understand that's weird for a REPL, but still...

like image 774
Dmitry Minkovsky Avatar asked Jun 17 '14 04:06

Dmitry Minkovsky


1 Answers

I rely on the mongo shell for executing database migrations. The correctness of my migrations are heavily reliant on whether the mongo shell commands are synchronous or asynchronous.

I haven't been able to find anything in the docs 😔 , so I wrote a test script:

var ops = [];
var numDocs = 1e5;

var time1 = +new Date();
for (var i = 0; i < numDocs; i++) {
  ops.push({
    insertOne: {
      document: {
        test: 'test',
      }
    }
  });
}
db.test_obj.bulkWrite(ops);
var time2 = +new Date();
var count1 = db.test_obj.count();

db.test_obj.update({}, {$set: {test: 'test2'}}, {multi: true});

var countA = db.test_obj.find({test: 'test'}).count();
var countB = db.test_obj.find({test: 'test2'}).count();
print('Inserting ' + numDocs.toString() + ' documents took: ' + ((time2 - time1) / 1000).toString() + 's');
print(count1);
print(countA);
print(countB);

Output:

> mongo --host <HOST> test-2.js
<MONGO INIT OUTPUT>
Inserting 100000 documents took: 16.258s
100000
0
100000

From this I gather that all operations in mongo shell are synchronous -- although there are no such guarantees! There might be some operations that aren't synchronous or some conditions in my script making it appear synchronous.

The logic is that if e.g. .bulkWrite() or .update() were async the .count() call afterwards would return a number lower than 100,000. However, another possible explanation is that .count() is playing catch-up, looping over the collection as the documents are being inserted/updated.

like image 71
qff Avatar answered Sep 23 '22 14:09

qff