mongo shell的同步/异步属性是什么?

时间:2014-06-17 04:14:02

标签: mongodb asynchronous

我习惯于将JavaScript作为非阻塞/异步,特别是在IO方面。这就是为什么mongo贝壳让我感到奇怪的原因。以MongoDb: The Definitive Guide

为例

(来自第31页):


例如,假设我们使用以下内容插入一百万个虚拟元素:

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

现在我们将尝试删除刚刚插入的所有文档,并测量所需的时间。首先,这是一个简单的删除:

> 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()

通过db.findOne()查看评论?这直接来自文本。像这样的流动对我来说并不奇怪,但这是你不知道的事情,直到你花了很长时间试图弄清楚什么是错的。你希望工作的东西。

那么,mongo shell的异步/同步处理是什么?我怎么知道会发生什么,以及何时以及如何碰撞IO操作如上所述。这记录在哪里?有没有办法让它异步工作,就像JS通常表现的那样?我理解REPL很奇怪,但仍然......

2 个答案:

答案 0 :(得分:3)

我依靠mongo shell来执行数据库迁移。我的迁移的正确性严重依赖于mongo shell命令是同步还是异步。

我无法在文档中找到任何内容,因此我编写了一个测试脚本:

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);

输出:

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

从此我认为mongo shell中的所有操作都是同步的 - 尽管没有这样的保证!可能有一些操作不同步或我的脚本中的某些条件使它看起来是同步的。

逻辑是,例如, .bulkWrite().update()异常.count()之后,会返回低于100,000的数字。但是,另一种可能的解释是.count()正在追赶,在插入/更新文档时循环遍历集合。

答案 1 :(得分:1)

也许这个关于mongo shell的同步和异步性质的问题可以通过作者稍后在书中写的内容来理解:


  

[shell]执行未确认的写入,然后在绘制提示之前检查上一次操作是否成功。因此,如果对集合执行一系列无效操作,使用有效操作完成,shell将不会抱怨:

> db.foo.insert({"_id" : 1}); db.foo.insert({"_id" : 1}); db.foo.count()
1
  

您可以通过调用getLastError手动强制检查shell,这会检查上一次操作的错误:

> db.foo.insert({"_id" : 1}); db.foo.insert({"_id" : 1}); print(
... db.getLastError()); db.foo.count()
E11000 duplicate key error index: test.foo.$_id_  dup key: { : 1.0 }
1
  

在为shell编写脚本时,这会很有用。


啊,哈,所以shell REPL实现了同步行为,因为它的操作是未确认的。