/nimongo

Pure Nim lang MongoDB driver

Primary LanguageNimMIT LicenseMIT

nimongo - Pure Nim MongoDB Driver Build Status nimble

nimongo has a main intention to provide developer-friendly way to interact with MongoDB using Nim programming language without any other dependencies.

You can find a table of supported features at the bottom of the document.

nimongo is tested on MongoDB 3.x.x and 4.0.x versions with GCC and MSVS2017 compiler backends and the latest stable version of Nim (0.19.0).

Installation

You can use nimble package manager to install nimongo. The most recent version of the library can be installed like this:

$ nimble install nimongo

or directly from Git repo:

$ nimble install https://github.com/SSPkrolik/nimongo.git

Current status (briefly)

Currently nimongo.mongo implements connection to single MongoDB server, and support for most widely used queries (whole CRUD with some exceptions),

nimongo.bson gives full support of current BSON specification. As for performance, it is comparable with pymongo Python driver on rough timeit-style tests.

Usage of synchronous client

nimongo.mongo.Mongo synchronous client perform interaction with MongoDB over network using sockets and blocking I/O which stops the thread it is used on from executing while MongoDB operation is not finished: either data is sent over network (insert, update, remove), or query (find) is done, and answer (or portion of it) is waited for.

Mongo synchronous client is thread-safe. It uses simple Lock when executing commands and queries.

import oids

import nimongo.bson  ## MongoDB BSON serialization/deserialization
import nimongo.mongo ## MongoDB client

## Create new Mongo client
var m = newMongo().slaveOk(true).allowPartial(false)

## Connect to Mongo server
let connectResult = m.connect()

## Specify collection
let collection = m["db"]["collectionName"]

## Create new bson document
let doc = %*{
  "name": "John"
}



## Insert document into DB
collection.insert(doc)

## Update [single] document
let reply = collection.update(%*{
  "name": "John"
}, %*{
  "$set": {
    "surname": "Smith"
  }
})

# Check command execution status
if reply.ok:
  echo "Modified a document."

## Delete multiple documents
let removeResult = collection.remove(%*{"name": "John"})

## Check how many documents were removed
if removeResult.ok:
  echo "Removed ", removeResult.n, " documents."

## Delete single document
collection.remove(%{"name": "John"}, limit=1)

## Delete collection
collection.drop()

## Delete single document
collection.remove(%{"name": "John"}, limit=1)

## Fetch number of documents in collection
collection.count()

## Fetch number of documents in query
let tally = collection.find(%*{"name": "John"}).count()

## Fetch one document from DB returning only one field: "name".
let fetched = collection.find(%*{"name": "John"}, @["name"]).one()

## Fetch all matching documents from DB receiving seq[Bson]
let documents = collection.find(%*{"name": "John"}).all()

## Fetch all matching documents as a iterator
for document in collection.find(%*{"name": "John"}).items():
  echo document

## Force cursor to return only distinct documents by specified field.
let documents = collection.find(%*{"name": "John"}).unique("name").all()

Usage of async client

nimongo.mongo.Mongo can also work in an asynchronous mode based on ayncdispatch standard async mechanisms, and asyncnet.AsyncSocket sockets. It performs non-blocking I/O via {.async.} procedures.

Mongo async client is thread-safe. It uses simple Lock when executing commands and queries.

import asyncdispatch  ## Nim async-supportive functions here
import oids

import nimongo.bson   ## MongoDB BSON serialization/deserialization
import nimongo.mongo  ## MongoDB client

## Create new Mongo client
var m: AsyncMongo = newAsyncMongo().slaveOk(false)  ## Still Mongo type

## Connect to Mongo server with asynchronous socket
let connected = waitFor(m.connect())

## Testing connection establishing result
echo "Async connection established: ", connected

## Inserting single document into MongoDB
waitFor(m.insert(B("hello-async", "victory")))

## Inserting multiple documents into MongoDB
let
  doc1 = %*{"doc1": 15}
  doc2 = %*{"doc2": "string"}

waitFor(m.insert(@[doc1, doc2]))

## Removing single document from MongoDB
waitFor(m.remove(B("doc1", 15), limit=1))

## Removing multiple documents from MongoDB
waitFor(m.remove(B("doc1", 15)))

Currently Supported Features

Here's a list of supported features with appropriate status icons:

  • - implemented feature
  • 🔴 - not implemented feature
  • ⚠️ - partly supported or unstable

BSON

nimongo.bson module implements full BSON specification, and includes means for developer-friendly BSON creation, modification, serialization and deserialization.

You can user either B(...) template or %* for documents creation depending on what is more convenient for you.

let doc = B("name", "John")("surname", "Smith")("salary", 100)
let doc2 = B(
    "name", "Sam")(
    "surname", "Uncle")(
    "salary", 1000)(
    "skills", @["power", "government", "army"]
    )

Authentication

nimongo supports the new SCRAM-SHA-1 challenge-response user authentication mechanism

var db: Database[Mongo]
try:
    db = newMongoDatabase("mongodb://$1:$2@localhost:27017/db" % [db_user,db_pass])
    if not db.client.authenticated: raise newException(AUTHError, "Unable to authenticate to db")
except:
    logging.error(getCurrentExceptionMsg())
    raise
    

MongoDB Features

This table represents MongoDB features and their implementation status within nimongo.mongo Nim module.

Block Feature Status (sync) Status (async) Notes
Connection 2 / 7 2 / 7
Single server
Replica set 🔴 🔴
Socket Timeout 🔴 🔴
SSL 🔴 🔴
Connect Timeout 🔴 🔴
Write Concern
Read Preference 🔴 🔴
Operations Insert (Single/Multiple), Remove (Single/Multiple), Update (Single/Multiple/Upsert)
Querying 6 / 10 5 / 9
Find one
Find all
Find iterator
Skip
Limit
Count
Tailable
Partial 🔴 🔴
FindAndModify 🔴 🔴
parallelCollectionScan 🔴 🔴
getLastError
Authentication 1 / 7 1 / 7
authenticate 🔴 🔴
SCRAM-SHA-1
MONGODB-CR 🔴 🔴
MONGODB-X509 🔴 🔴
GSSAPI (Kerberos) 🔴 🔴
PLAIN (LDAP SASL) 🔴 🔴
logout 🔴 🔴
User Management 2 / 7 2 / 7
Create User
Update User 🔴 🔴
Drop User
Drop all users 🔴 🔴
Grant roles 🔴 🔴
Revoke roles 🔴 🔴
Users info 🔴 🔴
Role Management 0 / 0 0 / 0
Replication 1 / 1 1 / 1
Is Master
Sharding 0 / 0 0 / 0
Instance Administration Commands 6 / 7 6 / 7
Copy DB 🔴 🔴
List databases
Drop database
List collections
Rename collection
Drop collection
Create collection
Diagnostic 0 / 0 0 / 0
GridFS 0 / 0 0 / 0
Indices 0 / 4 0 / 4
Create Index 🔴 🔴
Drop Index 🔴 🔴
Drop Indices 🔴 🔴
Ensure Index 🔴 🔴
Aggregation 3 / 6 3 / 6
aggregate 🔴 🔴
count
distinct Cursor.unique proc
group 🔴 🔴
mapReduce 🔴 🔴
orderBy
Geospatial 0 /3 0 / 3
geoNear 🔴 🔴
geoSearch 🔴 🔴
geoWalk 🔴 🔴
Auditing 0 / 1 0 / 1
logApplicationMessage 🔴 🔴

P.S. Contribution is welcomed :)