New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cant count result #195
Comments
This was previously asked in #178. In the new driver, a Cursor object now represents the actual results of an executed command or query, whereas cursors in the legacy driver had a dual-nature (pre- or post-executed). The legacy The userland library implements a I realize this may come across as an inconvenience, but I believe the explicit API is a ultimately a step forward from the legacy driver, where many users might have been oblivious to what was actually happening under the hood. Feel free to follow up if you have additional questions. |
Closing this out as I believe it was answered, but feel free to follow up if you have additional questions. |
The reasoning for taking out count(), sort(), and limit() I get. However, those are a ton of breaking changes for moving to the new driver here on a large application. Lots of rewriting unfortunately. My question, is where's an example of the new best practice for easily counting filtered results on http://mongodb.github.io/mongo-php-library/classes/collection/? It states: "MongoDB\Collection is perhaps the most useful class in this library. It provides methods for common operations on a collection, such as inserting documents, querying, updating, counting, etc.". However, there is no example of counting. Will you please provide the updated example using the code below of using MongoDB\Collection for counting?
It would be great on http://mongodb.github.io/mongo-php-library/ to see a complete list of breaking changes from the legacy mongo driver and new best practices code examples of their equivalents using the new mongodb driver and library. |
There is documentation at http://mongodb.github.io/mongo-php-library/api/class-MongoDB.Collection.html#_count, although that's not particularly useful or extensive. The original driver's count() method, does in fact, not do something with a cursor. It constructs the original query, and then runs that with a count command. In fact, this is what happens under the hood (old driver);
In the new driver, this behaviour is different:
I also wrote about this in an article: https://derickrethans.nl/new-drivers-part3-cursor.html |
Ah, I didn't see https://derickrethans.nl/new-drivers-part3-cursor.html. That would have saved a lot of time. Having a breaking changes section on mongo-php-library would be helpful. My two cents there. Would $count = $collection->count($filter); be the one liner of your example above? Seems like it works. The part I'm still confused about is $cursor->count() was removed because it could possibly be inaccurate, but we're still running the query twice, so what have we gained by not simply being able to call $cursor->count() other than pointing out the fact that it is not accurate? |
By removing the method from the Cursor class, we're forcing users to acknowledge that it is not a true count of the cursor's results. This goes hand in hand with eliminating the dual nature of the cursor (as MongoCursor had in the legacy extension) and its pre- and post-executed states -- along with the fact that The only accurate solution would be to use |
Does this mean the only way to iterate over a cursor, short of using |
@hackel There are two ways to retrieve the count. Either run the same filter through a count query $count = $collection->count($filter); or increment a counter while iterating over the cursor $cursor = $collection->find($filter);
$count = 0;
foreach ($cursor as $document) {
$count++;
} I can't recall exactly how the old |
In the legacy driver,
We do have PHPLIB-81 open to track the idea of creating an Iterator class that could decorate a |
@lindelius It's from Laravel's I ended up with this hacky solution, based on a stackoverflow post: $cursor = $collection->find(...);
$it = new \IteratorIterator($cursor);
$it->rewind();
while ($it->valid()) {
if (call_user_func($callback, $it) === false) {
return false;
}
$page++;
$cursor = $collection->find(next $page);
$it = new \IteratorIterator($cursor);
$it->rewind();
} I guess this is very similar to PHPLIB-81, but using the built-in The only other way I can think of to do this would be to count the iterations in a foreach loop as you described, then exit the outer loop if the resulting count is less than the page size after finishing the inner loop. Either that or running one extra query at the start to get the document count. I thought it might be possible to accomplish this with Mongo's |
Well, the first problem is that Laravel's Eloquent ORM is designed for SQL databases and the jenssegers/laravel-mongodb library is just a MongoDB wrapper for it. I refuse to use it for my projects (and I use Laravel and Lumen quite a lot) as it doesn't reflect how developers are supposed to work with MongoDB at all. I've created my own library (which wraps the official MongoDB PHP library) to give me the added functionality that I need for my projects. I'm actively using and updating it as I find more things that I need to add or change, so feel free to check it out and use it if it satisfies your needs (sorry for the plug). When it comes to the chunking, I'm not sure what exactly you are using it for, but the results from the database are already chunked up into batches, which means that you aren't loading the entire result set in from start. Also, if you are intending to chunk the results by requesting, say 20 documents at a time, using new calls to |
We already use IteratorIterator in the library to decorate a Cursor object (see: CollectionInfoCommandIterator). IteratorIterator is useful for decorating any Traversable and exposing methods to the underlying handlers (e.g. get current element/key, rewind, move forward). In this case, The downside of your approach is that you're executing one query for each page in sequence, which means more roundtrips and cursors/queries on the server side.
Pagination via index ranges is absolutely more performant than using |
Thanks for the feedback, @lindelius and @jmikola. Sorry for hijacking this issue into a support request, that was not my intention! @lindelius I completely agree, I had to learn the hard way about laravel-mongodb, and now it's too ingrained in this application to remove. Thanks for the plug, though! Your library looks intriguing. I'll definitely keep an eye on that for future projects. What I'm doing now is using limit/skip, actually. The collection is around 120k now, so not exactly "huge," but may grow a bit. To query by index ranges, would I have to add an extra indexed, auto-incrementing id field with predictable page boundaries, or can I just use _id with limit? Sort by _id and query each page with a limit and {_id: {$gt: $last_id}}`? I'm currently not experiencing any performance issues from MongoDB with skip/limit—it's all on the PHP side, but I'd definitely like to know the best way to do it. |
Since the first four bytes of the 12-byte ObjectID is a timestamp, values are generated in increasing order and can be used for sorting. There should be no need for an extra field or index. See this Stack Overflow thread for more info. |
ON previous mongo driver you had all the result functions ->count()
It seems the new driver lacks the counting function
$coleccion->find()->count() is missing, it is impossible to count result on phongo
The text was updated successfully, but these errors were encountered: