Skip to content

tal2/zig-mongodb-driver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

73 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mongodb Driver - written in Zig

Overview

  • A driver for interacting with mongodb servers written in Zig

Status: ⚠️ work-in-progress

zig version: 0.15.1

compatibility

  • currently aiming for mongodb v7.x and v8.x

connectivity

  • single server
  • replicaset
  • sharded
  • heartbeat
  • server selection

concurrency

  • single-thread
  • multi-thread

authentication

  • SCRAM-SHA-256
  • SCRAM-SHA-1
  • SASL Mechanisms
  • MONGODB-X509
  • PLAIN
  • GSSAPI
  • MONGODB-AWS
  • MONGODB-OIDC

basic commands

  • generic run command
  • insertOne
  • insertMany
  • findOne
  • find
  • updateOne
  • updateMany
  • deleteOne
  • deleteMany
  • replaceOne
  • countDocuments
  • estimatedDocumentCount
  • distinct

additional commands

  • findAndModify
  • kill cursors
  • end sessions
  • mapReduce
  • parallelCollectionScan
  • geoNear
  • geoSearch

advanced operations

  • aggregation pipeline
  • bulk write operations
  • sessions (implicit & explicit)
  • transactions
  • timeouts
  • write concern

compression support

  • no compression
  • snappy
  • zlib
  • zstd

Commands:

Initialize and Connect

  var conn_str = try ConnectionString.fromText(allocator, "mongodb://127.0.0.1/sandbox");
  defer conn_str.deinit(allocator);

  const server_api = ServerApi{
    .version = .v1,
    .strict = true,
    .deprecationErrors = true,
  };
  var db = try Database.init(allocator, &conn_str, server_api); // server api is optional, can be null
  defer db.deinit();

  const credentials = MongoCredential{
    .username = "...",
    .source = "...",
    .password = "...",
    .mechanism = .SCRAM_SHA_256,
    .mechanism_properties = null,
  };

  try db.connect(credentials);

Insert Command

  const doc1 = .{
    .name = "doc1"
  };
  const insert_response = try db.collection(collection_name).insertOne(doc1, .{});
  switch (insert_response) {
    .response => |response| {
        defer response.deinit(allocator);
        // ...
    },
    .write_errors => |write_errors| {
        defer write_errors.deinit(allocator);
        // ...
    },
    .err => |err| {
        defer err.deinit(allocator);
        // ...
    },
  }

Document Count Estimate

  const count_estimate = try db.collection(collection_name).estimatedDocumentCount(.{});
  switch (count_estimate) {
    .n => |n| {
        std.debug.print("estimated count: {d}\n", .{n});
    },
    .err => |err| {
        defer err.deinit(gpa);
        // ...
    },
  }

Replace Document Command

  const filter = .{ .name = "obj1-original" };
  const replacement = .{ .name = "obj1-replaced", .value = 42, .replaced = true };
  const replace_response = try db.collection(collection_name).replaceOne(filter, replacement, .{});
  switch (replace_response) {
    .response => |response| {
        defer response.deinit(allocator);
        // ...
    },
    .write_errors => |write_errors| {
        defer write_errors.deinit(allocator);
        // ...
    },
    .err => |err| {
        defer err.deinit(allocator);
        // ...
    },
  }

Update One Command

  const filter = .{ .name = "obj1" };
  const update = .{ .name = "obj1-updated", .updated = true };
  const update_response = try db.collection(collection_name).updateOne(filter, update, .{});
  switch (update_response) {
    .response => |response| {
        defer response.deinit(allocator);
        // ...
    },
    .write_errors => |write_errors| {
        defer write_errors.deinit(allocator);
        // ...
    },
    .err => |err| {
        defer err.deinit(allocator);
        // ...
    },
  }

Update Many Command - simple

  const filter = .{ .status = "pending" };
  const update = .{ .@"$set" = .{ .status = "completed" } };
  const update_response = try db.collection(collection_name).updateMany(filter, update, .{ .upsert = true });
  switch (update_response) {
    .response => |response| {
        defer response.deinit(allocator);
        // ...
    },
    .write_errors => |write_errors| {
        defer write_errors.deinit(allocator);
        // ...
    },
    .err => |err| {
        defer err.deinit(allocator);
        // ...
    },
  }

Update Many Command - chainable

  var update_chain = db.collection(collection_name).updateChain();
  defer update_chain.deinit();

  const update_chain_result = try update_chain
      .add(.{ .status = .{ .@"$eq" = "pending" } }, .{ .@"$set" = .{ .status = "started" } }, .{ .multi = true })
      .add(.{ .status = .{ .@"$eq" = "in-progress" } }, .{ .@"$set" = .{ .status = "completed" } }, .{ .multi = true })
      .exec(.{ .ordered = true });

  switch (update_chain_result) {
    .response => |response| {
        defer response.deinit(allocator);
        // ...
    },
    .write_errors => |write_errors| {
        defer write_errors.deinit(allocator);
        // ...
    },
    .err => |err| {
        defer err.deinit(allocator);
        // ...
    },
  }

Document Count

Document Count - count all

  const count = try db.collection(collection_name).countDocuments(.{});

Document Count - count with filter

  const filter = .{ .name = "doc1" }
  const count = try db.collection(collection_name).countDocuments(filter);

Delete Command

delete one

  const delete_filter = .{ .name = "doc1" };
  const delete_response = try db.collection(collection_name).deleteOne(delete_filter, .{});
  switch (delete_response) {
    .response => |response| {
        defer response.deinit(allocator);
        // ...
    },
    .write_errors => |write_errors| {
        defer write_errors.deinit(allocator);
        // ...
    },
    .err => |err| {
        defer err.deinit(allocator);
        // ...
    },
  }

delete all (by filter)

  const delete_filter = .{ .name = "doc1" };
  const delete_response = try db.collection(collection_name).deleteMany(delete_filter, .{});
  switch (delete_response) {
    .response => |response| {
        defer response.deinit(allocator);
        // ...
    },
    .write_errors => |write_errors| {
        defer write_errors.deinit(allocator);
        // ...
    },
    .err => |err| {
        defer err.deinit(allocator);
        // ...
    },
  }

Find Command

Find Command - find many

  const filter = .{ .name = .{ .@"$ne" = null } };
  const response = try db.collection(collection_name).find(filter, .all, .{
   .batchSize = 2,
   .limit = 6,
  });
  switch (response) {
    .cursor => {
        var cursor = response.cursor;
        defer cursor.deinit();
        while (try cursor.next()) |batch| {
          for (batch) |doc| {
              defer doc.deinit(allocator);
              // do something with doc
          }
        }
        try cursor.release(); // optionally call to kill cursor, if iterator not used till the end
    },
    .err => |err| {
      defer err.deinit(allocator);
      // ...
    },
  }

Find Command - find one

  const filter = .{ .name = .{ .@"$eq" = "doc1" } };
  const response = try db.collection(collection_name).findOne(filter, .{});
  switch (result) {
    .document => |doc| {
        defer doc.deinit(allocator);
        // ...
    },
    .err => |err| {
        defer err.deinit(allocator);
        // ...
    },
    .null => {
        // ...
    },
  }

Aggregate Command

  var pipeline_builder = PipelineBuilder.init(allocator);
  defer pipeline_builder.deinit();
  const pipeline = pipeline_builder
     .match(.{ .name = .{ .@"$ne" = null } })
     .sort(.{ .name = 1 })
     .group(.{ ._id = "$name", .count = .{ .@"$sum" = 1 } })
     // and more ...
     .build() catch |err| {
        std.debug.print("Error building pipeline: {}\n", .{err});
        return;
     };

  const response = try collection.aggregate(pipeline, .{}, .{});
  switch (response) {
    .cursor => {
        var cursor = response.cursor;
        defer cursor.deinit();
        // same as find command
    },
    .err => |err| {
          defer err.deinit(gpa);
          std.debug.print("Error releasing result: {}\n", .{err});
      },
  }

About

Mongodb Driver written in Zig - WIP

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages