Basic mongodb usage

Here is my simple attempt to query a MongoDB collection using the mongodb crate.
The compiler gives me an error for the cursor.next() call saying "method not found in MongoDB::Cursor. But I got the idea to try this from the official docs here: mongodb::Cursor - Rust.
What am I doing wrong?

use mongodb::Client;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let uri = "mongodb://127.0.0.1:27017";
    let mut client = Client::with_uri_str(uri).await?;

    let db = client.database("animals");
    let coll = db.collection("dogs");
    let cursor = coll.find(None, None).await?;
    while let Some(doc) = cursor.next().await {
        dbg!(doc);
    }

    Ok(())
}

The only dependencies in my Cargo.toml file are:

mongodb = { version = "1.1.1", default-features = false, features = ["async-std-runtime"] }
tokio = { version = "0.3", features = ["full"] }

The next method is part of the StreamExt trait from the futures crate. Try adding a dependency on that crate and importing the trait from it.

1 Like

That worked! It seems like the documentation for Cursor here should make that more clear.

https://docs.rs/mongodb/1.1.1/mongodb/struct.Cursor.html

For the benefit of others, I had to add the dependency "futures = "0.3.12" and add this in my main.rs file:

use futures::stream::StreamExt;
1 Like

I see you are doing this:

mongodb = { version = "1.1.1", default-features = false, features = ["async-std-runtime"] }
tokio = { version = "0.3", features = ["full"] }

You should not be mixing async-std and Tokio. Go for this instead:

mongodb = { version = "1.1.1", default-features = false, features = ["tokio-runtime"] }
tokio = { version = "0.3", features = ["full"] }

Edit: I see that mongodb is still on Tokio 0.2. Is that why you were doing that? Another option here would be to wrap mongodb usage in tokio-compat-02.

2 Likes

I copied those dependencies from an example I found on the web.
When I change it as you suggested, I get the error "thread 'main' panicked at 'there is no timer running, must be called from the context of Tokio runtime'".

I tried removing the tokio dependency since the mongodb crate already has that dependency, but then I get lots of errors including "use of undeclared crate or module tokio".

I tried putting the tokio dependency back in and using version 0.2 and that works. So that leaves me with two questions.

  1. Why doesn't the mongodb crate work with the latest version of tokio?
  2. Why do I have to include tokio as a dependency when the mongodb crate already has that as a dependency?

Because Tokio 0.2.x and 1.x.y are not compatible, and mongodb has not been updated yet. As I mentioned, there is a compatibility crate you can use.

Things are only available in your namespace if you mention it in your Cargo.toml. Otherwise removing any dependency from any crate would be a breaking change, as some downstream crate might be using one of the dependencies without their own import.

1 Like

I didn't realize that my code can only use dependencies mentioned in my Cargo.toml file and not ones that are dependencies of those. That's a difference from how Node.js works (and package.json) that probably catches people coming to Rust from there by surprise. Good to know!

That seems like a major issue in making backwards-compatible changes to Node.js libraries. It means that using a library for implementation details is impossible, because the list of dependencies is never an implementation detail, but part of the public API.

1 Like