MongoDB Rust Driver

repository·main·Indexed 23 days ago

https://github.com/mongodb/mongo-rust-driver

An officially supported client-side library for interacting with MongoDB deployments in Rust applications. It provides a fully asynchronous API built on tokio and an optional synchronous API. The driver supports Linux, MacOS, and Windows, requiring Rust 1.88.0+ and MongoDB 4.2+. Key features include support for various TLS providers, compression methods, and integration with web frameworks like Actix, Axum, and Rocket.

Tokens
56.7K
Snippets
93
Records
269
Agent score
80%

What's inside mongodb-mongo-rust-driver

  1. Understand the CRUD specification tests

    main

    The CRUD specification tests in this repository are designed to verify a driver's implementation of MongoDB's Create, Read, Update, and Delete operations. These tests are divided into two types:

    1. Platform-independent tests: Defined in YAML and JSON files using the Unified Test Format. These are used to exercise the driver's core CRUD logic across different environments.
    2. Prose tests: Complex scenarios that cannot be easily expressed in YAML/JSON. These require manual implementation within the driver to ensure specific edge cases (such as error detail exposure or batch splitting logic) are handled correctly.
  2. Manage Atlas Search Indexes

    main

    The MongoDB Rust driver provides helpers to manage Atlas Search indexes. Because search index management commands are asynchronous, the server returns before the changes are fully applied. To ensure an index is ready for use, you must repeatedly poll the cluster using listSearchIndexes until the index's queryable field is true.

    Key Concepts

    • Asynchronous Operations: Commands like createSearchIndex, createSearchIndexes, updateSearchIndex, and dropSearchIndex return before the index is fully operational.
    • Polling for Readiness: Use listSearchIndexes to check the status. An index is considered ready when its queryable property is true.
    • Timeouts: Search index operations can take time. It is recommended to use a generous timeout (e.g., 5 minutes) to avoid false-positive timeout errors.
    • Unique Collection Names: Due to server-side limitations regarding duplicate index names/definitions, it is a best practice to use randomly generated collection names (e.g., a hex representation of an ObjectId) when performing automated tests or frequent index lifecycle operations.
  3. How to benchmark libmongocrypt bindings

    main

    When benchmarking Client-Side Encryption (CSE) performance, drivers should aim to measure the cost of calling between the native language and the libmongocrypt C library.

    To isolate the performance of the bindings, it is preferred to use a bindings API that interfaces directly with the mongocrypt_t handle rather than using the high-level MongoClient API. Using the bindings API allows you to mock responses from the MongoDB server, narrowing the benchmark scope to the encryption/decryption logic itself. If direct access to mongocrypt_t is not available, you must use the MongoClient API, which will include the overhead of network communication with the MongoDB server in the results.

  4. Use OIDC Callbacks for authentication

    main

    The MongoDB driver supports OIDC callbacks, which allow you to provide custom logic for fetching access tokens.

    Key Behaviors:

    • Single Invocation: For multiple connections or high-concurrency operations (e.g., 10 threads running 100 operations each), the callback should ideally be called only once to retrieve the token for the client.
    • Validation: You can implement a callback that validates inputs and returns a valid access token. If the callback returns null or data that does not conform to the OIDCCredential format, the subsequent database operation will fail.
    • Error Handling: If the callback returns invalid tokens, the driver should handle the resulting authentication failure appropriately.
  5. Use rewrapManyDataKey to rotate keys

    main

    The rewrapManyDataKey method allows you to rotate data keys from a source provider to a destination provider.

    To perform a rewrap:

    1. Create a ClientEncryption object with the necessary kmsProviders.
    2. Call rewrapManyDataKey with a filter (to select specific keys) and the RewrapManyDataKeyOpts.
    3. The RewrapManyDataKeyOpts must include the provider (the destination KMS provider) and the masterKey for that destination provider.
  6. Perform Explicit Encryption and Decryption

    main

    You can manually encrypt and decrypt values using a ClientEncryption object. This is useful for controlling exactly when and how data is transformed before being sent to the server.

    Encryption Options

    When calling the encryption method, you can specify the algorithm and contentionFactor:

    • Indexed: Allows for equality queries on the encrypted field.
    • Unindexed: For fields that do not require querying.
    • contentionFactor: A value used to manage index contention (e.g., 0 or 10).

    Example Workflow

    1. Encrypt a value using clientEncryption.encrypt() with specific EncryptOpts.
    2. Insert the resulting payload into a collection using an encryptedClient.
    3. Decrypt the value back using clientEncryption.decrypt() to verify the roundtrip.
    // Encrypting an indexed value
    class EncryptOpts {
       keyId : <key1ID>,
       algorithm: "Indexed",
       contentionFactor: 0,
    }
    
    // Encrypting an unindexed value
    class EncryptOpts {
       keyId : <key1ID>,
       algorithm: "Unindexed",
    }
  7. Iterating Change Streams in Drivers

    main

    When implementing change stream iteration, drivers must handle blocking/non-blocking behavior carefully to avoid hanging the test runner:

    • Synchronous Drivers: Must provide a non-blocking mode of iteration.
    • Asynchronous Drivers: If only a blocking mode is available, do not iterate unnecessarily.
    • Conservative Iteration Strategy:
      • If the test expects an error: If no error was thrown during creation or operations, iterate the change stream once. This allows a getMore command to potentially throw the expected error.
      • If the test expects success: Iterate the change stream only until it returns the exact number of documents expected by the test.
  8. Configure AutoEncryption with credentialProviders

    main

    You can provide custom credential providers for Auto Encryption by including them within the autoEncryption field of the MongoClient options. This is useful for managing remote KMS credentials during automatic encryption/decryption operations.

    If you provide credentials directly in kmsProviders while also defining credentialProviders, the driver may throw an error. The intended pattern for remote providers is to leave kmsProviders empty for that provider and use credentialProviders to supply the secrets.

  9. Set up Auto Encryption with a Schema Map

    main

    Auto Encryption allows the driver to automatically encrypt fields based on a provided schema_map. The schema map defines which fields in a collection should be encrypted, the BSON type, the keyId, and the encryption algorithm (e.g., AEAD_AES_256_CBC_HMAC_SHA_512-Random).

    {
      "db.coll": {
        "bsonType": "object",
        "properties": {
          "encrypted_placeholder": {
            "encrypt": {
              "keyId": "/placeholder",
              "bsonType": "string",
              "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
            }
          }
        }
      }
    }
  10. Access Databases and Collections

    main

    Once you have a Client, you interact with the database via the Database handle.

    • Database handles: Obtained via client.database("name"). Like the Client, the Database handle is an Arc wrapper, making it cheap to clone and pass around.
    • Collections: You obtain handles to specific collections from a Database instance to perform data operations.
    • Bulk actions: The Database handle also provides access to several bulk operations that can be performed directly without navigating to a specific collection.
  11. Session Lifecycle and Error Handling

    main

    The driver enforces strict rules regarding the lifecycle of a ClientSession:

    • Post-Termination Usage: Once endSession has been called, no further operations (e.g., insert_one, find_one) can be performed using that session. The driver must report an error.
    • Client Ownership: A session is bound to the client that created it. Attempting to use a session created by client2 in an operation on a collection belonging to client1 must result in an error.
    • User Authentication: If the driver allows on-the-fly authentication changes, a session is tied to the authenticated user. If you logout user A and authenticate as user B, attempting to use user A's session must return an error.