cryomongo
Version, currently 0.17.319 versions
- 0.17.5latestSep 2, 2026
- 0.17.4not indexedSep 2, 2026
- 0.17.3not indexedSep 2, 2026
- 0.17.2not indexedSep 2, 2026
- 0.17.1not indexedSep 2, 2026
- 0.17.0not indexedSep 2, 2026
- 0.16.0not indexedSep 2, 2026
- 0.15.0not indexedSep 2, 2026
- 0.14.0not indexedSep 2, 2026
- 0.13.0not indexedSep 2, 2026
- 0.12.0not indexedSep 2, 2026
- 0.11.0not indexedSep 2, 2026
- 0.10.0not indexedSep 2, 2026
- 0.9.0not indexedSep 2, 2026
- 0.8.0not indexedSep 2, 2026
- 0.7.0not indexedSep 2, 2026
- 0.6.0not indexedSep 2, 2026
- 0.5.0not indexedSep 2, 2026
- 0.4.0not indexedSep 2, 2026
github.com/alumna/cryomongo
A MongoDB driver written in Crystal
Nothing has been indexed for 0.17.3 yet. The tag is recorded, its shard.yml has not been read, so the manifest and dependency list below are empty because they are unknown rather than because they are absent.
Installation
# Add this to your shard.yml
dependencies:
cryomongo:
github: alumna/cryomongo
version: ~> 0.17.3Then run:
shards installshard.yml
No shard.yml has been indexed for 0.17.3. You can read it on the repository.
Dependencies
Unknown: the shard.yml for this version has not been read yet.
README
This README is the one indexed from the repository at its latest ref, not from the tag for this version.
A MongoDB driver in Crystal (no mongo-c-driver). Tested against MongoDB 8.0. zstd wire compression links libzstd.
If you are looking for a higher-level object-document mapper, see
moongoon.
Contents
- This fork
- Features
- Installation
- Usage
- Conventions
- Connection
- Authentication
- Basic operations
- Bulk operations
- Indexes
- GridFS
- Change streams
- Raw commands
- Concerns and preference
- Commands and SDAM monitoring
- Causal consistency
- Transactions
- Benchmarks
- Contributing
- Contributors
This fork
alumna/cryomongo is a fork of elbywan/cryomongo. The work here is for MongoDB 8.0 (max wire version 25, OP_MSG-only) and Crystal 1.21. It is meant to merge into the upstream repository.
The driver is 0.x. Phases 1–3 of ROADMAP.md are done (CRUD, sessions, transactions, CSOT, load balancer, CMAP/SDAM, compression). Next is Phase 3.14 (performance). 1.0 waits on client-side encryption (Phase 4). Cloud auth (Phase 5: AWS / OIDC) is after 1.0.
Not in this fork: Atlas Search, MongoDB newer than 8.0, MONGODB-AWS, MONGODB-OIDC. Open work: ROADMAP.md.
Features
- CRUD - helpers, collection bulk, client
bulkWrite(MongoDB 8.0),let, legacycount, mapReduce,Database#drop/Collection#drop - Aggregation
- Read / write concerns and read preference
- Authentication - SCRAM-SHA-1/256 (SASLprep on SHA-256 passwords), X509, PLAIN
- TLS -
tlsCertificateKeyFilePassword; stapled OCSP unlesstlsDisableCertificateRevocationCheck - Indexes
- GridFS -
session:,delete_by_name/rename_by_name,drop - Change streams -
#nextwaits;#try_nextpolls; resume after a labeled getMore error - Tailable cursors and collation
- Standalone, replica set, sharded, load-balanced
- CSOT - URI / client / database / collection
timeoutMS; remaining time becomesmaxTimeMS - Wire compression - zlib, snappy, zstd (
compressors=) - Command monitoring - sensitive commands are redacted; CMAP subscribe; spec logs
MONGODB_LOG_* - Retryable reads and writes
- Causal consistency and transactions - pinned mongos; handshake retry on that pin
- Versioned API
- Raw commands -
command,Database#run_command/#run_cursor_command
Generated API pages live in docs/. That folder is stale until it is regenerated.
Installation
- Add the dependency to your
shard.yml:
dependencies:
cryomongo:
github: alumna/cryomongo
- Run
shards install
zstd wire compression links libzstd. On Debian/Ubuntu: sudo apt-get install libzstd-dev. snappy is pure Crystal. zlib is in the Crystal stdlib.
Usage
Minimal working example
require "cryomongo"
# Create a Mongo client, using a standard mongodb connection string.
client = Mongo::Client.new # defaults to: "mongodb://localhost:27017"
# Get database and collection.
database = client["database_name"]
collection = database["collection_name"]
# Perform crud operations.
result = collection.insert_one({ one: 1 })
# The driver adds `_id` when the document is a BSON. inserted_ids is on the result.
puts result.try(&.inserted_ids)
collection.replace_one({ one: 1 }, { two: 2 })
bson = collection.find_one({ two: 2 })
puts bson.try(&.["two"]) # => 2
collection.delete_one({ two: 2 })
puts collection.count_documents # => 0_i64
client.close
Complex example with serialization
require "cryomongo"
# We take advantage of the BSON serialization capabilities provided by the `bson.cr` shard.
record User,
name : String,
banned : Bool? = false,
_id : BSON::ObjectId = BSON::ObjectId.new,
creation_date : Time = Time.utc do
include BSON::Serializable
include JSON::Serializable
end
# Initialize Client, Database and Collection.
client = Mongo::Client.new
database = client["database"]
users = database["users"]
# We set majority read and write at the Database level.
database.read_concern = Mongo::ReadConcern.new(level: "majority")
database.write_concern = Mongo::WriteConcern.new(w: "majority")
# Drop and recreate the Collection to ensure that we read later only the documents we inserted in this example.
{ Mongo::Commands::Drop, Mongo::Commands::Create }.each do |command|
database.command(command, name: "users")
rescue e : Mongo::Error::Command
# ignore the server error, drop will fail if the collection has not been created before.
end
# Insert User structures that are automatically serialized to BSON.
users.insert_many(["John", "Jane"].map { |name| User.new(name: name) })
# Fetch a Cursor pointing to the users collection.
# `#each` (and `to_a`) close the cursor when iteration ends.
# You can also pass a block to `find`. Call `#close` if you use `#next` yourself.
cursor = users.find
# Iterate the cursor and use `.of(User)` to deserialize as the cursor gets iterated.
# Then push the users into an array that gets pretty printed.
puts cursor.of(User).to_a.to_pretty_json
# => [
# {
# "name": "John",
# "banned": false,
# "_id": {
# "$oid": "f2001c5fb0a33e0264e2ea05"
# },
# "creation_date": "2020-07-25T09:52:50Z"
# },
# {
# "name": "Jane",
# "banned": false,
# "_id": {
# "$oid": "f2001c5fb0a33e0264e2ea07"
# },
# "creation_date": "2020-07-25T09:52:50Z"
# }
# ]
Conventions
- Methods and arguments names are in snake case.
- Object arguments can usually be passed as a NamedTuple, Hash, BSON::Serializable or a BSON instance.
Connection
require "cryomongo"
# Mongo::Client is the root object for interacting with a MongoDB deployment.
# It is responsible for monitoring the cluster, routing the requests and managing the socket pools.
# A client can be instantiated using a standard mongodb connection string.
# Replica set:
# Mongo::Client.new("mongodb://localhost:27017/?replicaSet=rs0")
# Load balancer:
# Mongo::Client.new("mongodb://localhost:8000/?loadBalanced=true")
# CSOT (one deadline for selection, checkout, and maxTimeMS):
# Mongo::Client.new("mongodb://localhost:27017/?timeoutMS=5000")
# Client options can be passed as query parameters…
client = Mongo::Client.new("mongodb://address:port/database?appname=MyApp")
# …or with a Mongo::Options instance…
options = Mongo::Options.new(appname: "MyApp")
client = Mongo::Client.new("mongodb://address:port/database", options)
# …or both.
# Instantiate objects to interact with a specific database or a collection…
database = client["database_name"]
collection = database["collection_name"]
# …or using `default_database` if the connection uri string contains a default auth database component ("/database").
if database = client.default_database
collection = database["collection_name"]
end
# The overwhelming majority of programs should use a single client and should not bother with closing clients.
# Otherwise, to free the underlying resources a client must be manually closed.
client.close
# To enable SSL/TLS, use the `tls` option, alongside `tlsCAFile` and `tlsCertificateKeyFile`.
# Encrypted PEM keys use `tlsCertificateKeyFilePassword`.
uri = "mongodb://localhost:27017/?tls=true&tlsCAFile=./ca.crt&tlsCertificateKeyFile=./client.pem&tlsCertificateKeyFilePassword=secret"
ssl_client = Mongo::Client.new uri
# Wire compression. The driver uses the first name that the server also has.
uri = "mongodb://localhost:27017/?compressors=snappy,zlib,zstd"
client = Mongo::Client.new uri
# CSOT: remaining timeoutMS becomes maxTimeMS. timeoutMS=0 means no timeout.
client = Mongo::Client.new("mongodb://localhost:27017/?timeoutMS=5000")
Links
Authentication
Supported: SCRAM-SHA-1, SCRAM-SHA-256 (SASLprep on the password), X509, and PLAIN.
Not supported yet: MONGODB-AWS, MONGODB-OIDC.
require "cryomongo"
# Username and password. The server picks SCRAM-SHA-1 or SCRAM-SHA-256.
client = Mongo::Client.new("mongodb://username:password@localhost:27017")
# Or set the mechanism:
# mongodb://username:password@localhost:27017/?authMechanism=SCRAM-SHA-256
# mongodb://localhost:27017/?authMechanism=MONGODB-X509&tls=true
# mongodb://user:pass@localhost:27017/?authMechanism=PLAIN
Basic operations
require "cryomongo"
client = Mongo::Client.new
# Most CRUD operations are performed at collection-level.
collection = client["database_name"]["collection_name"]
# The examples below are very basic, but the methods can accept all the options documented in the MongoDB manual.
## Create
# Insert a single document
collection.insert_one({ key: "value" })
# Insert multiple documents
collection.insert_many((1..100).map { |i| { count: i } })
# To track the _id, generate and pass it as a property
id = BSON::ObjectId.new
collection.insert_one({ _id: id, key: "value" })
## Read
# Find a single document
document = collection.find_one({ _id: id })
document.try { |d| puts d.to_json }
# Find multiple documents.
cursor = collection.find({ qty: { "$gt": 4 }})
elements = cursor.to_a # cursor is an Iterator(BSON)
cursor.close # send killCursors if the server cursor is still open
## Update
# Replace a single document.
collection.replace_one({ name: "John" }, { name: "Jane" })
# Update a single document.
collection.update_one({ name: "John" }, { "$set": { name: "Jane" }})
# Update multiple documents
collection.update_many({ name: { "$in": ["John", "Jane"] }}, { "$set": { name: "Jules" }})
# Find one document and replace it
document = collection.find_one_and_replace({ name: "John" }, { name: "Jane" })
puts document.try &.["name"]
# Find one document and update it
document = collection.find_one_and_update({ name: "John" }, { "$set": { name: "Jane" }})
puts document.try &.["name"]
## Delete
# Delete one document
collection.delete_one({ age: 20 })
# Delete multiple documents
collection.delete_many({ age: { "$lt": 18 }})
# find_one_and_delete
document = collection.find_one_and_delete({ age: { "$lt": 18 }})
puts document.try &.["age"]
# Drop the collection (NamespaceNotFound is ignored) or the database.
collection.drop
client["database_name"].drop
# Aggregate
# Perform an aggregation pipeline query
cursor = collection.aggregate([
{"$match": { status: "available" }},
{"$limit": 5},
])
cursor.try &.each { |bson| puts bson.to_json }
# let variables (also on find, updates, deletes, find_one_and_*, bulk_write)
cursor = collection.aggregate(
[{"$match": {"$expr": {"$eq": ["$status", "$$st"]}}}],
let: { st: "available" },
)
# Map-Reduce (not retryable). Crystal uses output: because out is reserved.
inline = collection.map_reduce(
"function() { emit(this.status, 1) }",
"function(key, values) { return Array.sum(values) }",
output: {inline: 1},
)
# Distinct collection values
values = collection.distinct(
key: "field",
filter: { age: { "$gt": 18 }}
)
# Documents count (returns Int64)
counter = collection.count_documents({ age: { "$lt": 18 }})
# Estimated count (also Int64)
counter = collection.estimated_document_count
# Legacy count command (prefer count_documents). Empty filter omits query.
counter = collection.count({ age: { "$lt": 18 }})
# Raw command (not retryable; database read/write concern is not applied).
database = client["database_name"]
ping = database.run_command({ping: 1})
puts ping["ok"]
# Command that returns a cursor. getMore stays on the same server.
cursor = database.run_cursor_command({find: "collection_name", batchSize: 2}, batch_size: 2)
cursor.each { |doc| puts doc.to_json }
Links
Bulk operations
require "cryomongo"
client = Mongo::Client.new
# A Bulk object can be initialized by calling `.bulk` on a collection.
collection = client["database_name"]["collection_name"]
bulk = collection.bulk
# A bulk is ordered by default.
bulk.ordered? # => true
500.times do |idx|
# Build the queries by calling bulk methods multiple times.
bulk.insert_one({number: idx})
bulk.delete_many({number: {"$lt": 450}})
bulk.replace_one({ number: idx }, { number: idx + 1})
end
# Execute all the queries and return an aggregated result.
pp bulk.execute(write_concern: Mongo::WriteConcern.new(w: 1))
Client bulkWrite (MongoDB 8.0) can write to more than one namespace in one command:
result = client.bulk_write([
Mongo::ClientBulk::InsertOne.new("database_name.collection_name", {number: 1}),
Mongo::ClientBulk::DeleteOne.new("database_name.other", {number: 1}),
])
puts result.inserted_count
Links
Indexes
require "cryomongo"
client = Mongo::Client.new
collection = client["database_name"]["collection_name"]
# Create one index without options…
collection.create_index(
keys: {
"a": 1,
"b": -1,
}
)
# or with options (snake_cased)…
collection.create_index(
keys: {
"a": 1,
"b": -1,
},
options: {
unique: true
}
)
# and optionally specify the name.
collection.create_index(
keys: {
"a": 1,
"b": -1,
},
options: {
name: "index_name",
}
)
# Follow the same rules to create multiple indexes with a single method call.
collection.create_indexes([
{
keys: { a: 1 }
},
{
keys: { b: 2 }, options: { expire_after_seconds: 3600 }
}
])
Links
GridFS
require "cryomongo"
client = Mongo::Client.new
database = client["database_name"]
# A GridFS bucket belongs to a database.
gridfs = database.grid_fs
# Upload (using File.open ensures the file descriptor is closed automatically).
# All GridFS methods accept session: if you need a transaction or causal reads.
id = File.open("file.txt") do |file|
gridfs.upload_from_stream("file.txt", file)
end
# Download
stream = IO::Memory.new
gridfs.download_to_stream(id, stream)
puts stream.rewind.gets_to_end
# Find
files = gridfs.find({
length: {"$gte": 5000},
})
files.each do |file|
puts file.filename
end
# Delete by id or by filename
gridfs.delete(id)
gridfs.delete_by_name("file.txt")
# Rename by id or by filename
gridfs.rename(id, "new.txt")
gridfs.rename_by_name("file.txt", "new.txt")
# Drop the files and chunks collections
gridfs.drop
# And many more methods… (check the link below.)
Links
Change streams
require "cryomongo"
# Change streams can watch a client, database or collection for change.
# This code snippet will focus on watching a single collection.
client = Mongo::Client.new
collection = client["database_name"]["collection_name"]
spawn do
cursor = collection.watch(
[
{"$match": {"operationType": "insert"}},
],
max_await_time_ms: 10000
)
# `#each` / `#next` wait while the stream is open. An empty getMore does not stop.
# Use `#try_next` when you want one poll (and the latest resume_token) without blocking.
begin
cursor.of(BSON).each do |doc|
puts doc.document_key
puts doc.full_document.to_json
end
ensure
cursor.close
end
end
100.times do |i|
collection.insert_one({count: i})
end
sleep
Links
Raw commands
require "cryomongo"
# Commands can be run on a client, database or collection depending on the command target.
client = Mongo::Client.new
# Call the `.command` method to run a command against the server.
# The first argument is a `Mongo::Commands` sub-class, followed by the mandatory arguments
# and finally an *options* named tuple containing the optional parameters in snake_case.
result = client.command(Mongo::Commands::ServerStatus, options: {
repl: 0
})
puts result.to_bson
# The .command method can also be called against a Database…
client["database"].command(Mongo::Commands::Create, name: "collection")
client["database"].command(Mongo::Commands::Drop, name: "collection")
# …or a Collection.
client["database"]["collection"].command(Mongo::Commands::Validate)
Links
Concerns and Preference
require "cryomongo"
# Instantiate Read/Write Concerns and Preference
read_concern = Mongo::ReadConcern.new(level: "majority")
write_concern = Mongo::WriteConcern.new(w: 1, j: true)
read_preference = Mongo::ReadPreference.new(mode: "primary")
# They can be set at the client, database or client level…
client = Mongo::Client.new
database = client["database_name"]
collection = database["collection_name"]
client.read_concern = read_concern
database.write_concern = write_concern
collection.read_preference = read_preference
# …or by passing an extra argument when calling a method.
collection.find(
filter: { key: "value" },
read_concern: Mongo::ReadConcern.new(level: "local"),
read_preference: Mongo::ReadPreference.new(mode: "secondary")
)
Links
Commands and SDAM Monitoring
require "cryomongo"
client = Mongo::Client.new
# 1. Command Monitoring Subscriber
# Tracks the execution of database commands (e.g., find, insert, aggregate).
# Sensitive commands (authenticate, saslStart, createUser, …) are redacted.
cmd_subscription = client.subscribe_commands { |event|
case event
when Mongo::Monitoring::Commands::CommandStartedEvent
Log.info { "COMMAND.#{event.command_name} #{event.address} STARTED: #{event.command.to_json}" }
when Mongo::Monitoring::Commands::CommandSucceededEvent
Log.info { "COMMAND.#{event.command_name} #{event.address} COMPLETED (#{event.duration}s)" }
when Mongo::Monitoring::Commands::CommandFailedEvent
Log.info { "COMMAND.#{event.command_name} #{event.address} FAILED: #{event.failure.inspect} (#{event.duration}s)" }
end
}
# 2. SDAM (Server Discovery and Monitoring) Subscriber
# Tracks the lifecycle and topology changes of the MongoDB cluster.
sdam_subscription = client.subscribe_sdam { |event|
case event
when Mongo::Monitoring::SDAM::ServerDescriptionChangedEvent
Log.info { "SERVER.#{event.address} CHANGED: #{event.previous_description.type} -> #{event.new_description.type}" }
when Mongo::Monitoring::SDAM::TopologyDescriptionChangedEvent
Log.info { "TOPOLOGY CHANGED: #{event.previous_description.type} -> #{event.new_description.type}" }
when Mongo::Monitoring::SDAM::ServerHeartbeatStartedEvent
Log.info { "HEARTBEAT.#{event.address} STARTED awaited=#{event.awaited}" }
when Mongo::Monitoring::SDAM::ServerHeartbeatSucceededEvent
Log.info { "HEARTBEAT.#{event.address} OK awaited=#{event.awaited} (#{event.duration})" }
when Mongo::Monitoring::SDAM::ServerHeartbeatFailedEvent
Log.info { "HEARTBEAT.#{event.address} FAILED awaited=#{event.awaited}: #{event.failure}" }
when Mongo::Monitoring::SDAM::ServerClosedEvent
Log.info { "SERVER.#{event.address} REMOVED FROM TOPOLOGY" }
end
}
# 3. Connection pool (CMAP) subscriber
# Tracks pool create / ready / clear / close and checkout.
cmap_subscription = client.subscribe_cmap { |event|
case event
when Mongo::Monitoring::CMAP::PoolClearedEvent
Log.info { "POOL.#{event.address} CLEARED interrupt=#{event.interrupt_in_use_connections}" }
when Mongo::Monitoring::CMAP::ConnectionCheckedOutEvent
Log.info { "POOL.#{event.address} CHECKED OUT id=#{event.connection_id}" }
when Mongo::Monitoring::CMAP::ConnectionClosedEvent
Log.info { "POOL.#{event.address} CLOSED id=#{event.connection_id} reason=#{event.reason}" }
end
}
# Make some queries…
client["database_name"]["collection_name"].find({ hello: "world" })
# …and eventually at some point, unsubscribe the loggers.
client.unsubscribe_commands(cmd_subscription)
client.unsubscribe_sdam(sdam_subscription)
client.unsubscribe_cmap(cmap_subscription)
Optional spec logs (off unless you set env). MONGODB_LOG_ALL=debug turns every component on. Per component: MONGODB_LOG_COMMAND, MONGODB_LOG_TOPOLOGY, MONGODB_LOG_CONNECTION (debug is the usual value). MONGODB_LOG_PATH is stdout, stderr, or a file (default stderr). MONGODB_LOG_MAX_DOCUMENT_LENGTH truncates command and reply JSON (default 1000). MONGODB_LOG_SERVER_SELECTION is accepted; this driver does not emit those messages yet.
# Example: MONGODB_LOG_COMMAND=debug MONGODB_LOG_PATH=stderr crystal run app.cr
Links
- Mongo::Client#subscribe_commands
- Mongo::Client#unsubscribe_commands
- Mongo::Monitoring::Observable
- Mongo::Monitoring::CommandStartedEvent
- Mongo::Monitoring::CommandSucceededEvent
- Mongo::Monitoring::CommandFailedEvent
Causal Consistency
require "cryomongo"
client = Mongo::Client.new
# It is important to ensure that both read and writes are performed with "majority" concern.
# See: https://docs.mongodb.com/manual/core/causal-consistency-read-write-concerns/
client.read_concern = Mongo::ReadConcern.new(level: "majority")
client.write_concern = Mongo::WriteConcern.new(w: "majority")
# Reusing the original Mongodb example.
# See: https://docs.mongodb.com/manual/core/read-isolation-consistency-recency/#examples
current_date = Time.utc
items_collection = client["test"]["items"]
# MongoDB enables causal consistency in client sessions by default.
# This is the block syntax that creates, ends and passes the session to collection methods automatically.
items_collection.with_session do |items|
# Using a causally consistent session ensures that the update occurs before the insert.
items.update_one(
{ sku: "111", end: { "$exists": false } },
{ "$set": { end: current_date }}
)
items.insert_one({ sku: "nuts-111", name: "Pecans", start: current_date })
puts items.find.to_a.to_pretty_json
end
client.close
Links
Transactions
require "cryomongo"
# Initialize Client and Database instances.
client = Mongo::Client.new
database = client["db"]
collection = database["collection"]
# Create the collection.
{Mongo::Commands::Drop, Mongo::Commands::Create}.each do |command|
database.command(command, name: "collection")
rescue e : Mongo::Error::Command
# ignore the server error, drop will fail if the collection has not been created before.
end
# Set read and write concerns to perform isolated transactions.
# See: https://docs.mongodb.com/master/core/transactions/#transactions-and-sessions
transaction_options = Mongo::Session::TransactionOptions.new(
read_concern: Mongo::ReadConcern.new(level: "snapshot"),
write_concern: Mongo::WriteConcern.new(w: "majority")
)
# There are two ways to perform transactions:
collection.with_session(default_transaction_options: transaction_options) do |collection, session|
puts collection.find.to_a.to_json # => "[]"
# 1. by calling the `with_transaction` method.
# `with_transaction` will commit after the block ends.
# if the block raises, the transaction will be aborted.
session.with_transaction do
collection.insert_one({_id: 1})
collection.insert_one({_id: 2})
end
puts collection.find.to_a.to_json # => [{"_id":1},{"_id":2}]
# The transaction below will be aborted because the block raises an Exception.
begin
session.with_transaction do
collection.insert_one({_id: 3})
raise "Interrupted!"
collection.insert_one({_id: 4})
end
rescue e
puts e # => Interrupted!
end
puts collection.find.to_a.to_json # => [{"_id":1},{"_id":2}]
# 2. by calling the `start_transaction`, `commit_transaction` and `abort_transaction` methods.
session.start_transaction
collection.insert_one({_id: 3})
# The transaction is isolated, reading outside of the session scope does not return documents impacted by the transaction…
puts database["collection"].find.to_a.to_json # => [{"_id":1},{"_id":2}]
# but reading within the session scope does.
puts collection.find.to_a.to_json # => [{"_id":1},{"_id":2},{"_id":3}]
session.commit_transaction
# The transaction is now committed and visible outside of the transaction scope.
puts collection.find.to_a.to_json # => [{"_id":1},{"_id":2},{"_id":3}]
puts database["collection"].find.to_a.to_json # => [{"_id":1},{"_id":2},{"_id":3}]
end
Links
- Mongo::Session#with_transaction
- Mongo::Session#start_transaction
- Mongo::Session#commit_transaction
- Mongo::Session#abort_transaction
- Mongo::Session::TransactionOptions
Benchmarks
See BENCHMARK.md (how to run, then the numbers). BSON-only: crystal run bench/driver_bench.cr. Live tasks need MONGODB_URI. A number you can quote: shards build --release driver_bench then BENCH_FULL=1. JSON history: bench/results/.
Contributing
- Fork it (https://github.com/alumna/cryomongo/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
Spec CI runs crystal spec -Dpreview_mt -Dexecution_context with CRYSTAL_WORKERS=2 and compressors=snappy,zstd,zlib (snappy is first, so the suite uses snappy; zlib and zstd run in compression prose). UTF holds one cluster lock per JSON file so failCommand and step-down do not overlap. Live prose that talks to mongod uses the same lock. Retryable writes wait for a replica-set primary instead of sending the first write to a lone Unknown seed (GitHub 27017 is often a secondary). Replica-set leftover failCommand is turned off with directConnection (long poll heartbeat, no URI userinfo) so an Unknown member cannot keep it.
Contributors
- elbywan - creator and maintainer
- paulocoghi - contributor
Credit
- Icon made by Smashicons from www.flaticon.com.
Documentation
Built from the current release. The first visit to a release nobody has asked for starts its build.
Links
This release
- Version
0.17.3- Tagged
- Sep 2, 2026
- Commit
7a6027c3f1ac- Indexed
- not yet
Dependents
Repository
github.com/alumna/cryomongo
Metadata
- Created
- Sep 3, 2026
- Updated
- Sep 23, 2026
- Synced
- Sep 23, 2026
- Versions
- 19