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

Dmi*_*sky 5 asynchronous mongodb

我已经习惯了JavaScript是非阻塞/异步的,尤其是在IO方面。这就是为什么mongo外壳让我感到奇怪的原因。从MongoDb:权威指南中获取以下示例:

(从第31页开始):


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

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

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

> 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()
Run Code Online (Sandbox Code Playgroud)

看到那个评论了db.findOne()吗?这直接来自文字。颠簸这样的流对我来说并不完全奇怪,但是直到您花了很长时间试图弄清楚您希望工作的地方出了什么问题时,您才知道这种事情。

那么,与mongoshell 进行异步/同步处理是什么?我应该如何知道会发生什么,以及何时以及如何颠覆IO ops,就像上面的那样。这在任何地方都有记录吗?有没有什么办法可以使其像JS通常一样正常工作?我知道这对于REPL很奇怪,但是仍然...

qff*_*qff 5

我依靠mongo shell来执行数据库迁移。我迁移的正确性在很大程度上取决于mongo shell命令是同步的还是异步的。

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

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);
Run Code Online (Sandbox Code Playgroud)

输出:

> mongo --host <HOST> test-2.js
<MONGO INIT OUTPUT>
Inserting 100000 documents took: 16.258s
100000
0
100000
Run Code Online (Sandbox Code Playgroud)

从中我可以看出mongo shell中的所有操作都是同步的 -尽管没有这样的保证!可能有些操作不同步,或者脚本中的某些条件使其看起来是同步的。

逻辑是,如果例如.bulkWrite().update()异步,则.count()随后的呼叫将返回小于100,000的数字。但是,另一个可能的解释是.count()正在追赶,在插入/更新文档时在集合上循环。


Dmi*_*sky 1

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

\n\n
\n\n
\n

[shell] 执行未确认的写入,然后在绘制提示之前检查最后一个操作是否成功。因此,如果您对集合执行一系列无效操作,并以有效操作结束,shell 不会抱怨:

\n
\n\n
> db.foo.insert({"_id" : 1}); db.foo.insert({"_id" : 1}); db.foo.count()\n1\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

您可以通过调用 getLastError 在 shell 中手动强制进行检查,该检查会检查上次操作的错误:

\n
\n\n
> db.foo.insert({"_id" : 1}); db.foo.insert({"_id" : 1}); print(\n... db.getLastError()); db.foo.count()\nE11000 duplicate key error index: test.foo.$_id_  dup key: { : 1.0 }\n1\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

这在为 shell 编写脚本时非常有用。

\n
\n\n
\n\n

啊,ha\xe2\x80\x94,所以 shell REPL 实现了同步行为,因为它的操作是未确认的。

\n