Currently it's pretty hard to get a correct, never-ending loop on a change stream cursor.
This is not right:
let cursor = db.foo.watch();
while (cursor.hasNext()) {
printjson(cursor.next());
}
because the cursor will return false from hasNext() whenever it gets an empty batch back from the server, even though the cursor is still open and there will eventually be a next change. Fortunately, we added a isExhausted() which will only return true if there is nothing left in the cursor and the server has closed the cursor, so there will never be anything else. Sadly, this is still not quite right:
cursor = db.foo.watch();
while (!cursor.isExhausted()) {
printjson(cursor.next());
}
because cursor.next() will first check whether hasNext() returns true, so if there is ever an empty batch, this will result in an error like the following:
foo:PRIMARY> cursor.next() 2017-12-07T17:05:04.624-0500 E QUERY [thread1] Error: error hasNext: false : DBCommandCursor.prototype.next@src/mongo/shell/query.js:843:1 @(shell):1:1
The correct way to do a never-ending loop like this over a tailable cursor is as follows:
cursor = db.foo.watch(); while (!cursor.isExhausted()) { if (cursor.hasNext()) { printjson(cursor.next()); } }
This seems overly confusing. It would be easier if the second example would work and cursor.next() would just automatically wait on cursors that are not exhausted but do not yet have a next result.